Kotlin中Dispatchers.Default适用场景及IO调度器性能疑问
为什么你的“CPU密集型”任务在Dispatchers.IO上跑得更快?
首先得说,你的测试结果看起来反直觉,但问题出在你写的任务并不是真正的纯CPU密集型任务,这才导致了Dispatchers.IO表现更好。咱们一步步拆解:
1. 你的blockingWork藏着“非CPU密集”的细节
你写的循环里有两个很容易被忽略的点,它们让线程不会一直占满CPU:
- 每次循环都新建
Random(System.currentTimeMillis()):对象创建本身有开销,而且System.currentTimeMillis()是需要调用系统内核的操作,会让线程短暂让出CPU,进入等待状态。 - 虽然看着一直在循环,但这些操作并没有让CPU核心100%运转,线程会有零星的空闲窗口。
这时候,Dispatchers.IO的高线程上限(你的8核机器上是64)就发挥了作用:当某个线程因为调用系统时间而短暂空闲时,调度器可以立刻切换到另一个等待的任务,让更多任务在1秒的时间窗口内交错执行,最终整体完成时间被压缩到1.3秒左右。
2. Dispatchers.Default的批次执行限制
在你的8核CPU上,Dispatchers.Default的最大并行度是8——也就是同一时间最多跑8个线程。24个任务会被分成3批执行,每批8个任务各跑1秒左右,加起来总时间自然接近3秒,和你的测试结果完全吻合。
那为什么还要用Dispatchers.Default?
这就要回到调度器的设计初衷了:
- 真正的CPU密集型任务:如果你的任务是纯计算(比如矩阵运算、复杂加密、大量数值计算),这些任务会把CPU核心占满100%。这时候Dispatchers.Default的线程数等于CPU核心数是最优选择——因为上下文切换会带来额外开销,多线程反而会拖慢效率,这时候无切换的并行才是最快的。
- 避免资源浪费:Dispatchers.IO的高线程数是为IO密集型任务设计的(比如数据库查询、网络请求、文件读写),这些任务大部分时间在等待IO完成,线程处于空闲状态。如果用它跑纯CPU密集任务,会导致大量线程竞争CPU,频繁的上下文切换会消耗额外的CPU资源,反而降低整体效率。
验证一下:写个真正的CPU密集任务
把你的blockingWork改成纯计算的版本,再测试试试:
fun trueCpuIntensiveWork() { val startTime = System.currentTimeMillis() var count = 0L while (System.currentTimeMillis() - startTime < 1000) { // 纯粹的计算操作,不涉及系统调用或对象创建 count += 1 count *= 2 count /= 2 } }
这时候你会发现,Dispatchers.Default的执行速度会明显快于Dispatchers.IO——因为每个任务占满CPU核心,多线程的上下文切换会成为IO调度器的负担。
总结一下:你的测试任务因为包含系统调用和对象创建,不是纯CPU密集型,才让IO调度器有了发挥空间。针对不同任务类型选对调度器才是关键:CPU密集用Default,IO密集用IO,UI操作用Main。
内容的提问来源于stack exchange,提问作者alisabzevari
相关产品推荐
相关产品推荐

