Kotlin协程:runBlocking与coroutineScope执行结果差异疑问
问题原因
核心差异在于coroutineScope与runBlocking的行为逻辑:
coroutineScope是挂起函数,会挂起当前协程,直到其作用域内所有子协程执行完毕才继续向下执行。所以coroutine()中,coroutineScope会等待1000个launch协程(至少绝大多数)执行完num +=1后,才会执行println,因此能得到累加后的数值。runBlocking的作用是阻塞当前线程运行内部协程代码,但它的代码块是同步执行的:循环启动所有launch后,会立刻执行println或return语句,此时所有launch里的delay(10)还未执行,num +=1根本没机会运行,所以输出0。
修复方法
只需让runBlocking内部等待所有子协程完成即可,以下是几种常用实现方式:
方式1:用coroutineScope包裹启动逻辑
借助coroutineScope等待子协程的特性,修改代码如下:
suspend fun runBlocked() = runBlocking { var num = 0 coroutineScope { for (i in 1..1000) { launch { delay(10) num += 1 } } } println("Run blocking: $num") }
方式2:收集所有Job并调用joinAll()
手动保存每个launch返回的Job对象,统一等待所有任务完成:
suspend fun runBlocked() = runBlocking { var num = 0 val jobs = mutableListOf<Job>() for (i in 1..1000) { val job = launch { delay(10) num += 1 } jobs.add(job) } jobs.joinAll() println("Run blocking: $num") }
方式3:针对返回值场景的async+awaitAll()
如果是需要返回结果的场景,可改用async配合awaitAll():
suspend fun runBlockedWithReturn(): Int = runBlocking { var num = 0 val deferreds = mutableListOf<Deferred<Unit>>() for (i in 1..1000) { val deferred = async { delay(10) num += 1 } deferreds.add(deferred) } deferreds.awaitAll() return@runBlocking num }
注:你提到coroutine()的结果不是1000,是因为num +=1是非原子操作,多协程并发修改存在竞态条件,这部分逻辑你已经理解,此处不再赘述。
内容的提问来源于stack exchange,提问作者hc0re
相关产品推荐
相关产品推荐

