kotlin 如何在不改变返回类型的情况下从runBlocking返回主线程

3htmauhk  于 2023-03-09  发布在  Kotlin
关注(0)|答案(1)|浏览(161)

我有一个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

p1tboqfb

p1tboqfb1#

协程是围绕结构化并发的概念设计的,这基本上意味着并发操作被构造成一棵任务树,较大的任务由子任务组成并拥有子任务。
默认情况下,当我们使用launch()async()启动一个新的协程时,它会自动成为当前任务的一部分。在所有子任务完成之前,我们无法完成当前任务。其中一个子任务的失败会影响父任务。取消父任务会自动取消子任务,等等。
这正是runBlocking()等待doHeavyWork()的原因。使用launch()并不重要--这个繁重的任务仍然是runBlocking()的子任务,所以runBlocking()不能在繁重的任务之前完成。使用return@runBlocking也不能解决这个问题。
而且这种行为是有意的。否则你很容易就可以泄漏这些繁重的后台工作。如果后台任务崩溃了,你要等待它的结果,那该怎么办?如果它在处理过程中挂起了,那该怎么办?如果你不再需要这些后台工作,那该怎么办?如果我们假设后台任务不是一个“发射并忘记”的工作单元,而实际上,这是更大任务的一部分。
当然,有时候我们真的需要调度一个任务,它不是我们当前执行上下文的一部分。我们希望它与调用者完全异步地运行。对于这种情况,协程引入了作用域,它就像独立的任务树。使用作用域,你可以在另一个树中启动一个任务,而不是在你自己的树中。
根据您的情况,您可能希望使用预定义的作用域之一,例如在Android中,我们有lifecycleScopeviewModelScope等作用域,它们与不同Android组件的生命周期相关。您可以使用CoroutineScope()创建自己的作用域,但在这种情况下,您应该根据文档手动处理此作用域的生命周期。或者,您可以使用GlobalScope,它提供了一个真正的触发和忘记行为,但正是由于这个原因,不鼓励使用它。
如果您决定了要使用的作用域,那么就不需要使用runBlocking(),而是直接使用该作用域启动:

val myList = doMainActivity()

scope.launch {
    doHeavyWork()
}

return myList

相关问题