You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 06:30:44