为何用Dispatcher.Main/Default运行协程结果相似?调度器作用解析
关于协程调度器的两个问题解答
为什么Dispatcher.Main和Dispatcher.Default运行结果相似?
关键在于你示例里用了runBlocking——这是个阻塞式的协程构建器,会把当前线程牢牢卡住,直到内部所有协程都执行完才放行。不管子runBlocking指定的是Main还是Default调度器,父协程都会原地等待子协程跑完,再继续执行后续代码。
所以你看到的输出顺序完全一致:先打外部日志,子协程delay(1000)后打内部日志,最后打后续日志,总耗时都是1秒左右。调度器的线程差异被runBlocking的阻塞特性给掩盖了。
要是把内部的runBlocking换成launch(非阻塞构建器),差异马上就出来了:
- 用
Dispatchers.Default的话,子协程会在后台线程跑,父协程不等它,直接就打印After child coroutine...,之后才会打出子协程的内部日志。 - 用
Dispatchers.Main的话,在Android这类UI环境里,子协程会跑在主线程,但同样不会阻塞父协程;要是在普通Java/Kotlin程序里用Main调度器,直接就会报错——因为没有UI主线程的Looper支持。
我们为什么要使用调度器?
调度器说白了就是协程的「线程分配员」,核心作用是给不同类型的任务分配最合适的运行线程/线程池,主要解决这几个问题:
- UI操作必须用Dispatcher.Main:在Android、iOS这些平台,UI组件只能由主线程更新,用
Main调度器能确保协程跑在主线程,避免UI崩溃。 - CPU密集型任务用Dispatcher.Default:比如大数据排序、复杂计算,
Default调度器的线程数和CPU核心数匹配,能把CPU性能拉满,不会因为单线程导致卡顿。 - IO密集型任务用Dispatcher.IO:比如网络请求、文件读写,这类任务大部分时间在等IO响应,
IO调度器可以动态扩容线程池,不会让线程空等浪费资源。 - 自定义调度器满足特殊需求:如果业务要求必须在特定线程池(比如数据库连接池的线程)执行任务,还能自己定制调度器来实现。
总结下来,调度器就是让你能根据任务类型精准控制协程的运行环境,既保证程序性能,又符合平台的规则限制。
内容的提问来源于stack exchange,提问作者asodisc
相关产品推荐
相关产品推荐

