gpt4 book ai didi

multithreading - 为什么 'withContext' 不切换 'runBlocking' 下的协程?

转载 作者:行者123 更新时间:2023-12-04 06:42:28 29 4
gpt4 key购买 nike

想了解一下kotlin协程的执行顺序和线程切换。我用了withContext切换到另一个上下文并运行耗时的任务,因此主线程不会被阻塞。但是 kotlin 并没有像预期的那样切换上下文。

代码在 kotlin 操场上运行:https://pl.kotl.in/V0lbCU25K

不起作用的情况

suspend fun main() = runBlocking {
println("Hello, world!!!")
println(Thread.currentThread().name)
withContext(Dispatchers.IO) {
println("Before heavy load: ${Thread.currentThread().name}")
Thread.sleep(5000)
println("After heavy load: ${Thread.currentThread().name}")
}
println("waiting")
println(Thread.currentThread().name)
}

输出
Hello, world!!!
main @coroutine#1
Before heavy load: DefaultDispatcher-worker-1 @coroutine#1
After heavy load: DefaultDispatcher-worker-1 @coroutine#1
waiting
main @coroutine#1
sleep上述代码块中的函数在与主线程相同的线程中运行并阻塞它。

以下情况符合我的预期(耗时任务不会阻塞主线程)

情况1
suspend fun main() = runBlocking {
println("Hello, world!!!")
println(Thread.currentThread().name)
launch {
println("Before heavy load: ${Thread.currentThread().name}")
Thread.sleep(5000)
println("After heavy load: ${Thread.currentThread().name}")
}
println("waiting")
println(Thread.currentThread().name)
}


输出
Hello, world!!!
main @coroutine#1
waiting
main @coroutine#1
Before heavy load: main @coroutine#2
After heavy load: main @coroutine#2

案例2
suspend fun main() = runBlocking {
println("Hello, world!!!")
println(Thread.currentThread().name)
launch {
withContext(Dispatchers.IO) {
println("Before heavy load: ${Thread.currentThread().name}")
Thread.sleep(5000)
println("After heavy load: ${Thread.currentThread().name}")
}
}
println("waiting")
println(Thread.currentThread().name)
}

输出
Hello, world!!!
main @coroutine#1
waiting
main @coroutine#1
Before heavy load: DefaultDispatcher-worker-1 @coroutine#2
After heavy load: DefaultDispatcher-worker-1 @coroutine#2

最佳答案

I used withContext to switch to another context and run time consuming tasks, so the main thread won't be blocked. But kotlin did not switch context as expected.



您的 withContext call 确实释放了主线程。它将工作转移到另一个线程,但此时您的主线程无事可做,只能等待 withContext调用完成。 runBlocking启动一个事件循环,它可以为任意数量的并发协程提供服务,但由于您只有一个,因此必须完成一个协程才能获得 runBlocking block 完成。

这是线程未被阻塞的含义的演示:
fun main() {
measureTimeMillis {
runBlocking {
launchManyCoroutines()
println("Top-level coroutine sleeping on thread ${currentThread().name}")
delay(2_000)
println("Top-level coroutine done")
}
}.also { println("Program done in $it milliseconds") }

}

private fun CoroutineScope.launchManyCoroutines() {
val cpuCount = getRuntime().availableProcessors()
(1 until cpuCount).forEach { coroId ->
launch { // on the main thread
val sum = withContext(Dispatchers.Default) {
println("Coroutine #$coroId computing on thread ${currentThread().name}")
computeResult()
}
println("Coroutine #$coroId done on thread ${currentThread().name}:" +
" sum = $sum")
}
}
(cpuCount + 1..100).forEach { coroId ->
launch { // on the main thread
println("Coroutine $coroId sleeping 1 s on thread ${currentThread().name}")
delay(1_000)
println("Coroutine #$coroId done on thread ${currentThread().name}")
}
}
}

private fun computeResult(): Int {
val rnd = ThreadLocalRandom.current()
return (1..1_000_000).map { rnd.nextInt() }.sum()
}

该程序在主线程上启动(100 + 个可用处理器)并发协程。他们中的一些人使用 withContext(Dispatchers.Default)在线程池上执行 CPU 密集型任务(总计一百万个随机整数),而其他任务则直接在主线程上执行暂停工作(延迟一秒)。最后,顶级协程在完成前休眠 2 秒。

整个程序在 2 秒以上的时间内完成并打印如下内容:
Top-level coroutine sleeping on thread main

Coroutine #2 computing on thread DefaultDispatcher-worker-2
Coroutine #3 computing on thread DefaultDispatcher-worker-3
Coroutine #4 computing on thread DefaultDispatcher-worker-5
Coroutine #1 computing on thread DefaultDispatcher-worker-1
Coroutine #5 computing on thread DefaultDispatcher-worker-6
Coroutine #6 computing on thread DefaultDispatcher-worker-4
Coroutine #7 computing on thread DefaultDispatcher-worker-8

Coroutine 9 sleeping 1 s on thread main
Coroutine 10 sleeping 1 s on thread main
...
Coroutine 99 sleeping 1 s on thread main
Coroutine 100 sleeping 1 s on thread main

Coroutine #3 done on thread main: sum = -1248358970
Coroutine #4 done on thread main: sum = -228252033
Coroutine #6 done on thread main: sum = -147126590
Coroutine #2 done on thread main: sum = -1065374439
Coroutine #1 done on thread main: sum = -2029316381
Coroutine #7 done on thread main: sum = -865387844
Coroutine #5 done on thread main: sum = -1695642504

Coroutine #9 done on thread main
Coroutine #10 done on thread main
...
Coroutine #99 done on thread main
Coroutine #100 done on thread main

Top-level coroutine done
Program done in 2066 milliseconds

请注意,程序所做的一切都是在主协程在主线程上休眠时发生的。

关于multithreading - 为什么 'withContext' 不切换 'runBlocking' 下的协程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58794816/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com