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

为什么Kotlin中runBlocking会按顺序执行协程?

协程输出顺序差异:runBlocking vs coroutineScope

原代码(runBlocking版本)

fun main(){
    println("start")
    runBlocking {
        for (i in 0..10){
            launch {
                delay(2000L)
                println(i)
            }
        }
    }
    println("end")
}

输出结果:

start
0
1
2
3
4
5
6
7
8
9
10
end

改写后的代码(coroutineScope + suspend main版本)

suspend fun main(){
    println("start")
    coroutineScope {
        for (i in 0..10){
            launch {
                delay(2000L)
                println(i)
            }
        }
    }
    println("end")
}

输出特点:

数字0-10为随机顺序输出

现象原理分析

1. runBlocking的调度器特性

runBlocking默认使用BlockingEventLoop,它的事件循环运行在当前线程(单线程模式)。循环启动的11个协程会被依次加入这个单线程的事件队列。

每个协程执行delay(2000L)后会挂起,2秒后重新进入事件队列等待执行。由于事件队列是**先进先出(FIFO)**的规则,第一个启动的协程(i=0)会最先被调度恢复,接着是i=1,以此类推,最终输出自然有序。

简言之:runBlocking默认单线程调度,挂起协程恢复时按启动顺序排队执行,所以输出有序。

2. suspend main + coroutineScope的调度器特性

当使用suspend fun main()时,Kotlin默认分配Dispatchers.Default调度器——这是一个基于线程池的多线程调度器。

coroutineScope会继承外层的调度器,因此循环启动的协程会被分配到线程池的不同线程中执行。delay(2000L)结束后,各个协程的恢复时间受线程调度的不确定性影响:哪个协程所在的线程先空闲、被调度,哪个就先输出数字,最终呈现随机顺序。

简言之:suspend main默认用多线程调度器,协程在不同线程恢复,执行顺序由线程调度决定,所以输出随机。

补充验证

如果给runBlocking指定多线程调度器,输出也会变成随机顺序,直接印证调度器是核心原因:

fun main(){
    println("start")
    runBlocking(Dispatchers.Default) { // 指定多线程调度器
        for (i in 0..10){
            launch {
                delay(2000L)
                println(i)
            }
        }
    }
    println("end")
}

内容的提问来源于stack exchange,提问作者Max0r

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 14:40:15