Composing suspending functions

Minsuk Jang·2021년 10월 10일
0
post-thumbnail

코루틴 공식 문서

Sequential by default

  • doSomethingUsefulOne() -> doSomethingUsefulTwo() 순으로 진행된다.
fun main(args : Array<String>) = runBlocking{
    val time = measureTimeMillis {
        val one = doSomethingUsefulOne()
        val two = doSomethingUsefulTwo()
        println("The answer is ${one + two}")
    }

    println("Completed in $time ms ")
}

suspend fun doSomethingUsefulOne() : Int{
    delay(1000L)
    return 13
}

suspend fun doSomethingUsefulTwo() : Int{
    delay(1000L)
    return 29
}

Concurrent using async

  • 계산 속도를 향상시키기 위해 async를 이용한다.
  • 개념상으로 async와 launch는 동일하다(Deferred도 일종의 job).

launch와 async의 차이점은 반환값이다. (launch = job / async = deferred)

  • launch는 job(결과 값이 없는)을 반환한다.
  • async는 Deferred(미래에 값을 제공하겠다고 약속하는) 을 반환한다.
fun main(args : Array<String>) = runBlocking{
    val time = measureTimeMillis {
        val one = async {
            doSomethingUsefulOne()
        }
        val two = async {
            doSomethingUsefulTwo()
        }

        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}

첫 번째 방법보다 시간이 1초 앞 당겨진 것을 확인할 수 있다.

Lazily started async

  • async 블록의 처리 시점을 뒤로 미룰 수 있다.
  • 지연된 async 블록의 경우, start() 함수는 async 블록을 실행시키지만 수행 결과를 반환하지 않는다.
  • start() 함수는 await() 함수와 다르게 완료될 때까지 기다리지 않는다.
fun main(args : Array<String>) = runBlocking{
    val time = measureTimeMillis {
        val one = async(start = CoroutineStart.LAZY) {
            doSomethingUsefulOne()
        }
        val two = async(start = CoroutineStart.LAZY) {
            doSomethingUsefulTwo()
        }

        one.start()
        two.start()

        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}

await() 함수만 사용한 경우, Sequential by default와 비슷한 결과를 확인할 수 있다.

지연 시작을 왜 사용할까?? 🤔

Structured concurrency with async

  • 새로운 코루틴은 코루틴 자신의 생명주기를 한정짓는 특정한 CoroutineScope 내에서 실행되어야 한다.
  • Structured concurrency는 많은 코루틴들이 잃어버리거나 메모리 누수되지 않도록 보장해준다

Structured conccurrency 👌

  • two가 Exception을 던지면서 같은 coroutineScope에 있는 one도 종료된다.
fun main(args : Array<String>) = runBlocking<Unit>{
    val time = measureTimeMillis {
        try {
            failedConcurrentSum()
            //val one = somethingUsefulOneAsync()
            //val two = somethingUsefulTwoAsync()

            one.start()
            two.start()

            println("The answer is ${one.await() + two.await()}")
        } catch (e: ArithmeticException) {
            println("Computation failed with ArithmeticException")
        }
    }

    println("Time : $time ms...")
}

suspend fun failedConcurrentSum() : Int = coroutineScope {
    val one = async<Int> {
        try{
            delay(Long.MAX_VALUE)
            42
        }finally {
            println("First child was cancelled")
        }
    }

    val two = async<Int> {
        println("Second child throws an exception")
        throw ArithmeticException()
    }

    one.await() + two.await()
}

Structured conccurrency ❎

  • somethingUsefulOneAsync() 와 somethingUsefulTwoAsync() 가 다른 GlobalScope내에 존재하기 때문에 somethingUsefulOneAsync() 함수가 결과를 반환할 때까지 somethingUsefulTwoAsync() 함수는 대기한다.
fun main(args : Array<String>) = runBlocking<Unit>{
    val time = measureTimeMillis {
        try {
            //failedConcurrentSum()
            val one = somethingUsefulOneAsync()
            val two = somethingUsefulTwoAsync()

            one.start()
            two.start()

            println("The answer is ${one.await() + two.await()}")
        } catch (e: ArithmeticException) {
            println("Computation failed with ArithmeticException")
        }
    }

    println("Time : $time ms...")
}


suspend fun somethingUsefulOneAsync() = GlobalScope.async {
    doSomethingUsefulOne()
}

suspend fun somethingUsefulTwoAsync() = GlobalScope.async {
    doSomethingUsefulTwo()
}

suspend fun doSomethingUsefulOne() : Int{
    delay(Long.MAX_VALUE)
    throw ArithmeticException()
}

suspend fun doSomethingUsefulTwo() : Int{
    delay(1000L)
    return 29
}

참고

코틀린 코루틴 제어

profile
Positive Thinking

0개의 댓글