咨询:GlobalScope.launch在runBlocking主函数中未完成任务的原因
为什么GlobalScope.launch里的任务没完成?
嘿,这个问题的核心原因其实是程序过早退出,和GlobalScope的特性直接挂钩:
runBlocking只会等待它自己作用域内的协程执行完毕,但GlobalScope.launch创建的是全局作用域的独立协程,完全不受runBlocking的管控。- 你的
main函数里,runBlocking代码块只做了一件事:启动GlobalScope的协程,之后就没有其他代码了。这意味着runBlocking会立刻结束,整个JVM进程随即退出——此时GlobalScope里的协程还没来得及跑完那10次循环(每次还要等100ms),文件写入操作自然就没机会完成,最后就得到了空文件。
你可以做个小测试验证这个逻辑:在runBlocking代码块的最后加一行delay(2000),你会发现文件能正常写入内容,因为这时候程序没有立刻退出,给了GlobalScope协程足够的执行时间。但这显然不是正经的解决办法。
正确的解决方案有两种:
1. 抛弃GlobalScope,使用runBlocking的作用域启动协程
这是最推荐的方式,因为这样协程会被runBlocking管辖,runBlocking会自动等待它完成:
fun main() = runBlocking<Unit> { launch { // 直接使用runBlocking的作用域,无需GlobalScope val file = File(javaClass.getResource("/coroutines_file.txt").path) file.printWriter().use { out -> repeat(10) { i -> delay(100) out.println(i.toString()) } } } }
2. 手动等待GlobalScope的协程完成(不推荐)
如果因为某些原因非要用GlobalScope,你可以把协程的Job对象保存下来,调用join()让runBlocking等待它执行完毕:
fun main() = runBlocking<Unit> { val job = GlobalScope.launch { val file = File(javaClass.getResource("/coroutines_file.txt").path) file.printWriter().use { out -> repeat(10) { i -> delay(100) out.println(i.toString()) } } } job.join() // 手动等待全局协程完成 }
最后再提一句:
GlobalScope之所以不被推荐,就是因为它的协程脱离了任何作用域的管控,很容易出现这种“任务没跑完程序就结束”的问题,甚至会导致协程泄露。日常开发中尽量使用带明确生命周期的协程作用域,比如自定义CoroutineScope等。
内容的提问来源于stack exchange,提问作者HaKIM
相关产品推荐
相关产品推荐

