我有一个main函数需要返回一些值,而我有一个suspend函数,它只需要在调用main函数时在后台触发
fun mainFunc(): List<Int> {
if (noInteger)
return emptyList
val myList = doMainActivity()
runBlocking{
launch {
doHeavyWork()
}
}
return myList
}
suspend func doHeavyActivity(){
delay(5000L)
}
现在使用这个,它是按顺序运行的,这不会达到我的目的。我希望我的main在繁重的工作完成之前返回。
我试过了
runBlocking{
launch {
doHeavyWork()
}
return@Runblocking myList
}
当它要求我改变主函数的返回类型时,如果我改变了它,我就不能返回emptyList,并且必须改变所有调用函数,不确定调用mainFunc()的其他函数将如何使用return@Runblocking
1条答案
按热度按时间p1tboqfb1#
协程是围绕结构化并发的概念设计的,这基本上意味着并发操作被构造成一棵任务树,较大的任务由子任务组成并拥有子任务。
默认情况下,当我们使用
launch()
或async()
启动一个新的协程时,它会自动成为当前任务的一部分。在所有子任务完成之前,我们无法完成当前任务。其中一个子任务的失败会影响父任务。取消父任务会自动取消子任务,等等。这正是
runBlocking()
等待doHeavyWork()
的原因。使用launch()
并不重要--这个繁重的任务仍然是runBlocking()
的子任务,所以runBlocking()
不能在繁重的任务之前完成。使用return@runBlocking
也不能解决这个问题。而且这种行为是有意的。否则你很容易就可以泄漏这些繁重的后台工作。如果后台任务崩溃了,你要等待它的结果,那该怎么办?如果它在处理过程中挂起了,那该怎么办?如果你不再需要这些后台工作,那该怎么办?如果我们假设后台任务不是一个“发射并忘记”的工作单元,而实际上,这是更大任务的一部分。
当然,有时候我们真的需要调度一个任务,它不是我们当前执行上下文的一部分。我们希望它与调用者完全异步地运行。对于这种情况,协程引入了作用域,它就像独立的任务树。使用作用域,你可以在另一个树中启动一个任务,而不是在你自己的树中。
根据您的情况,您可能希望使用预定义的作用域之一,例如在Android中,我们有
lifecycleScope
或viewModelScope
等作用域,它们与不同Android组件的生命周期相关。您可以使用CoroutineScope()创建自己的作用域,但在这种情况下,您应该根据文档手动处理此作用域的生命周期。或者,您可以使用GlobalScope,它提供了一个真正的触发和忘记行为,但正是由于这个原因,不鼓励使用它。如果您决定了要使用的作用域,那么就不需要使用
runBlocking()
,而是直接使用该作用域启动: