Coroutines - async function with dispatcher

Hello!

I’m struggle with understanding what’s the difference between two code snippets (except syntax ;)) and why those two scenarios give different results.

Let’s consider we have a blocking function which I’m going to use in two examples:

    private fun randomIntBlocking(): Int {
        Thread.sleep(1000)
        val randomValue = Random.nextInt()
        println("${Thread.currentThread().name} - I'm done! $randomValue")
        return randomValue
    }
  1. Scenario 1:
    @Test
    fun `async - async in the main function`() = runBlocking {
        val deferred1 = async(Dispatchers.Default) { randomIntBlocking() }
        val deferred2 = async(Dispatchers.Default) { randomIntBlocking() }
        val deferred3 = async(Dispatchers.Default) { randomIntBlocking() }
        println(deferred1.await())
        println(deferred2.await())
        println(deferred3.await())
    }

If I run this code all executions of randomIntBlocking are done in parallel and we’ve got the output:

DefaultDispatcher-worker-1 @coroutine#2 - I'm done! 1934764997
DefaultDispatcher-worker-3 @coroutine#4 - I'm done! -144097372
DefaultDispatcher-worker-2 @coroutine#3 - I'm done! 541287634
1934764997
541287634
-144097372
  1. Scenario 2
   @Test
    fun `async - function internal async`() = runBlocking {
        val deferred1 = asyncFunctionWithDispatcher()
        val deferred2 = asyncFunctionWithDispatcher()
        val deferred3 = asyncFunctionWithDispatcher()
        val deferred4 = asyncFunctionWithDispatcher()
        println(deferred1.await())
        println(deferred2.await())
        println(deferred3.await())
        println(deferred4.await())
    }

    suspend fun asyncFunctionWithDispatcher(): Deferred<Int> = coroutineScope {
        println("${Thread.currentThread().name} - before async")
        async(Dispatchers.Default) { randomIntBlocking() }
    }

However,in this case, all randomIntBlocking() are done sequantially

main @coroutine#1 - before async
DefaultDispatcher-worker-1 @coroutine#2 - I'm done! -696818037
main @coroutine#1 - before async
DefaultDispatcher-worker-1 @coroutine#3 - I'm done! 546231453
main @coroutine#1 - before async
DefaultDispatcher-worker-1 @coroutine#4 - I'm done! -1402903086
-696818037
546231453
-1402903086

I can see that in the second scenario only one worker thread is used. What is the essential difference between those two snippets?

coroutineScope() suspends until all its children completes, so your second scenario is really similar as you would invoke async() and then await()/join() immediately.

2 Likes

ok, thank you!