为什么如果我不向async调用传递Dispatcher,这段Kotlin异步代码会按顺序运行?

huangapple go评论53阅读模式
英文:

Why does this Kotlin async code run sequentially if I don't pass a Dispatcher to the async call?

问题

If the following code is run it can be seen that it runs in parallel, as the output looks like this:

In thread DefaultDispatcher-worker-2 B
BBIn thread DefaultDispatcher-worker-1 A
ABABAABBAAABABAABABABABABABABABAABABABAABBABABAABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAABABABABABAAABBABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB
BBBBB

however if I remove the Dispatchers.Default from the async calls, it appears to run sequentially:

In thread main A
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
In thread main B
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

Why is this? Do you always have to specify a dispatcher to get parallel behavior?

英文:

If the following code is run it can be seen that it runs in parallel, as the output looks like this:

> In thread DefaultDispatcher-worker-2 B
BBIn thread DefaultDispatcher-worker-1 A
ABABAABBAAABABAABABABABABABABABAABABABAABBABABAABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAABABABABABAAABBABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB
BBBBB

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.runBlocking


fun main() {
    
    fun long(s: String): Int {
        println("In thread ${Thread.currentThread().name} $s ")
        repeat(100_000) {
            if (it % 1000 == 0) {
                print(s)
            }
        }
        println()
        return 1
    }

    suspend fun doIt() =
        coroutineScope {
            val a = async(Dispatchers.Default) {
                long("A")
            }
            val b = async(Dispatchers.Default) {
                long("B")
            }
        }

    runBlocking {
        doIt()
    }
}

however if I remove the Dispatchers.Default from the async calls, it appears to run sequentially:

> In thread main A
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
In thread main B
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

Why is this ? Do you always have to specify a dispatcher to get parallel behaviour ?

答案1

得分: 3

当你从协程范围中调用launchasync时,它会将协程调度到该范围的调度程序中。

因此,当你从主函数的runBlocking中调用函数doIt时,你会将协程的执行安排到单线程的Dispatcher.Main中。

结果是,范围内的所有协程都会按顺序执行。

要更改这一点,你可以为整个函数doIt切换上下文:

suspend fun doIt() =
    coroutineScope {
        withContext(Dispatchers.Default) {
            val a = async {
                long("A")
            }
            val b = async {
                long("B")
            }
        }
    }

或者你可以在调用doIt之前切换调度程序:

runBlocking {
    withContext(Dispatchers.Default) {
        doIt()
    }
}

现在,每个新的协程将被调度到默认调度程序,这是一个多线程的调度程序。

英文:

When you call launch or async from a coroutine scope it schedule the coroutine to execute in the scope's dispatcher.

So when you call function doIt from runBlocking at main function, you schedule coroutine execution to the single threaded Dispatcher.Main.

As result all coroutines in the scope will be executed sequently.

To change it you can switch context for the whole function doIt

suspend fun doIt() =
        coroutineScope {
            withContext(Dispatchers.Default) {
                val a = async {
                    long("A")
                }
                val b = async {
                    long("B")
                }
            }
        }

or you can switch dispatcher before doIt call

runBlocking {
    withContext(Dispatchers.Default) {
        doIt()
    }
}

Now each new coroutine will be scheduled to Default scheduler which is a multi threaded one.

huangapple
  • 本文由 发表于 2023年6月8日 23:38:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76433550.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定