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

为何不给Kotlin async指定Dispatcher时代码会串行执行?

为什么Kotlin协程指定Dispatcher.Default时并行,移除后串行?

现象复现

并行执行场景

运行以下代码时,协程会并行执行,输出内容相互交织:

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()
    }
}

串行执行场景

如果移除async调用中的Dispatchers.Default,代码会变为串行执行,输出按顺序出现:

In thread main A
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
In thread main B
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

原因分析

核心逻辑在于协程调度器(Dispatcher)决定了协程的执行线程池,以及是否具备并行能力:

  1. 指定Dispatchers.Default时:
    • Dispatchers.Default是基于共享线程池的调度器,默认线程数等于CPU核心数(至少2个)。
    • 两个async块会被分配到不同的工作线程执行,long函数这类CPU密集型任务会同时运行,因此输出交织,呈现并行效果。
  2. 不指定Dispatcher时:
    • async会继承当前协程的上下文。这里doIt在runBlocking的上下文执行,而runBlocking默认使用调用它的线程(此处是main线程)作为执行线程,且该上下文是单线程的。
    • long是普通阻塞同步代码,没有任何挂起点(suspend函数调用),第一个async会持续占用main线程直到执行完毕,才会轮到第二个async运行,最终表现为串行。

是否必须指定Dispatcher才能实现并行?

不是必须,但需要满足以下任一条件:

  • 显式指定支持多线程的调度器(如Dispatchers.Default、Dispatchers.IO),让协程能分配到不同线程并行执行;
  • 当前协程的上下文本身就是多线程调度器(比如在launch(Dispatchers.Default)内部启动async),此时async会继承该上下文,无需额外指定。

注意:CPU密集型任务优先用Dispatchers.Default,IO密集型任务(如网络请求、文件读写)更适合用Dispatchers.IO。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 23:25:15