为何该Kotlin协程程序执行耗时10秒而非15秒?
Kotlin协程程序耗时与阻塞操作问题解答
1. 为什么总耗时是10秒而非15秒?
launch会启动一个独立的协程,它和runBlocking内部的主协程是并发执行的:
launch块里的逻辑:循环5次,每次延迟1秒后打印数字,整个过程共耗时5秒。- 主协程的逻辑:打印"Suspending....."后延迟10秒,最后输出"Finish"。
两个协程同时运行,总耗时由耗时更长的任务决定(也就是主协程的10秒),不是两者耗时相加。在主协程等待的10秒里,launch的协程早就完成了它的5秒任务,所以整体程序在10秒后结束。
2. 是否跳过了等待环节?
完全没有跳过等待:
launch协程里的5次delay(1000)都会完整执行,数字0到4会在程序启动后的第1到5秒依次打印出来。- 主协程的
delay(10000)也会老老实实等够10秒,才会打印"Finish"。
两者只是借助协程的非阻塞挂起特性,在同一个线程上交替执行,不存在任何跳过等待的情况。
3. 换成真实耗时操作(比如数据库访问)会怎样?
这得看耗时操作是不是挂起函数:
- 如果是挂起式耗时操作(比如用支持协程的数据库客户端,操作被封装成挂起函数):
效果和delay一模一样,两个任务还是并发执行,总耗时依然由最长的任务决定(比如数据库操作总耗时5秒,主协程等10秒,整体就耗时10秒)。 - 如果是阻塞式同步操作(比如直接调用普通JDBC接口,没做挂起包装,也没切换到
Dispatcher.IO线程池):
阻塞操作会占着当前线程(runBlocking默认用调用它的线程),主协程的delay必须等阻塞操作完成才能继续执行。这时候总耗时就变成两个任务的时间相加(比如数据库操作5秒 + 主协程等待10秒 = 15秒)。
要避免这种阻塞,建议把阻塞式操作放到withContext(Dispatchers.IO)里执行,这样任务会被放到专门的线程池,不会占用主协程的线程,就能恢复并发执行的特性。
内容的提问来源于stack exchange,提问作者Anton Zyablov
相关产品推荐
相关产品推荐

