英文:
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
当你从协程范围中调用launch
或async
时,它会将协程调度到该范围的调度程序中。
因此,当你从主函数的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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论