첫번째와 두번째의 제일 큰 차이 점은 Scope의 차이입니다.
suspend fun getTotalUserCount() : Int {
coroutineScope {
launch(Dispatchers.IO) {
delay(1000)
count = 50
}
deferred = async(Dispatchers.IO) {
delay(3000)
return@async 70
}
}
return count + deferred.await()
}
>>>>> getTotalUserCount begins
>>>>> getTotalUserCount.lauch begins
>>>>> getTotalUserCount.async begins
>>>>> getTotalUserCount.lauch ends count = 50
>>>>> getTotalUserCount.async ends
>>>>> getTotalUserCount return called
>>>>> getTotalUserCount: 120
첫번째는 확장함수를 통해 Coroutine Scope을 한 개 생성하고 동일한 Scope 안에서 모든 동작이 수행됩니다. 따라서 coroutineScope 내부의 모든 job들이 완료될 때까지 대기하게 됩니다. coroutineScoped 블록이 완전히 처리되고 50 + 70 이 리턴됩니다.
하지만 두번째는
CoroutineScope(Dispatchers.IO).launch {
}
val deferred = CoroutineScope(Dispatchers.IO).async {
}
return count + deferred.await()
>>>>> getTotalUserCount begins
>>>>> getTotalUserCount.launch begins
>>>>> getTotalUserCount return called. count = 0
>>>>> getTotalUserCount.async begins
>>>>> getTotalUserCount.launch ends
>>>>> getTotalUserCount.async ends
>>>>> getTotalUserCount: 70
이렇게 CorountineScope 생성자를 통해 각기 다른 CoroutineScope을 두개 생성했기 때문에 lauch와 async는 다른 하나가 끝날 때까지 기다려 주지 않습니다. 그렇기 때문에 launch 블록은 혼자 독립적으로 실행이 되고 끝나고 deferred.await이 결과를 받을 때까지 대기하게 됩니다. 따라서 count 의 값은 return이 호출될 때의 값인 0이 되고 deferred 의 결과는 70이 됩니다.
CoroutineScope(Dispatchers.IO).launch {
}
val deferred = CoroutineScope(Dispatchers.IO).async {
}.await()
return count + deferred
위처럼 await를 return 전에 호출하면 동일한 결과 값이 나옴을 알 수 있습니다. 하지만 어떻게 Scope을 생성하고 배치하느냐에 따라 다른 결과가 나오기가 쉽습니다. 따라서 최대한 직관적으로 이해가 갈 수 있도록 코드를 짜야할 필요가 있습니다.