IT/Kotlin

Coroutine Async

물통꿀꿀이 2020. 11. 22. 16:22

코루틴에서 기본인 것 같지만 놓치는 부분이 있을 수도 있기에 정리해보려고 한다.

Async

async는 자주 사용해왔던 launch와 거의 흡사하다. 그러나 차이점이라면 launch는 job을 반환하는데에 비해 async는 Deferred라는 값을 반환한다. (아래 참조)

fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> (source)

그렇다면 Deferred가 무엇이길래 조금 다른 것일까?

엄밀히 말하면 Deferred도 job의 종류 중 하나이긴 한데 Deferred는 말 그대로 결과는 나중에 알려주겠다는 의미이다.

await()라는 메소드를 통해 값을 얻을 수 있기 때문에 실행 중 스레드를 block 하지 않는다.

suspend fun concurrentSum(): Int = coroutineScope {
    val one = async { doSomethingUsefulOne() }
    val two = async { doSomethingUsefulTwo() }
    one.await() + two.await()
}

때문에 위의 코드에서 확인 할 수 있듯이, one/two는 각각의 코루틴에서 실행되고 await를 통해 값을 얻고 합쳐진다.

Lazy async

Async를 좀 더 재미있게 쓸 수도 있다. 바로 lazy를 통한 것인데 코드로 먼저 확인해 보자. 

val time = measureTimeMillis {
    val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
    val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
    // some computation
    one.start() // start the first one
    two.start() // start the second one
    println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")

async의 CoroutineStart에 Lazy를 넣을 수 있다.

그런데 사실 Lazy를 쓰고 않쓰고는 결과상의 차이는 없다. 단지, await()를 호출 하는 시점에 코루틴을 시작한다는 점이 조금 다를 수 있다. (기존에는 async에서 바로 코루틴이 실행되었기 때문에)