使用kotlin coroutines的最新稳定版本,我试图使用它来实现我的应用程序功能之一。但是,我有点困惑。
基本上,我有一个函数可以对项目列表进行一些处理。大约需要700-1000毫秒。
fun processList(list : ArrayList<String>) : ArrayList<Info> {
val result = mutableListOf<Info>()
for (item in list) {
// Process list item
// Each list item takes about ~ 15-20ms
result.add(info) // add processed info to result
}
return result // return result
}
现在,我希望它不会阻塞主线程。因此,我将在启动块内启动此函数,以便它不会阻塞主线程。
coroutineScope.launch(Dispatchers.Main) {
val result = processList(list)
}
那很好。
但是,我试图使该函数成为挂起函数,以确保该函数不会阻塞主线程。实际上,在函数内部没有其他任何协程启动。还尝试在单独的协程中处理每个列表项,然后将它们全部加入以使其实际使用子协程。但是该循环内部的块使用了同步方法调用。因此,使其异步是没有意义的-并行。所以我最终有了这样的暂停功能:
suspend fun processList(list : ArrayList<String>) : ArrayList<Info> = coroutineScope {
val result = mutableListOf<Info>()
for (item in list) {
// Process list item
// Each list item takes about ~ 15-20ms
result.add(info) // add processed info to result
}
return result // return result
}
开始处只有一个suspend修饰符,方法块用coroutineScope { }
包装。
这还重要吗?哪一个更好?我应该仅在使用协程的情况下才使函数挂起功能,还是应该将长时间运行的功能标记为挂起功能?
我很困惑。我已经看过最近有关协程的所有讨论,但不清楚这一点。
有人可以帮我理解吗?
更新:
所以我最终拥有这样的功能。只是为了确保从未在主线程上调用该函数。并且调用函数不必到处都记住需要在后台线程上调用它。通过这种方式,我可以使调用函数的事物变得抽象:只需执行所告诉的一切,我就不在乎您要在哪里处理事物。只需处理并给我结果即可。因此,该函数可以自行处理需要运行的位置,而不是在调用函数上运行。
suspend fun processList(list : ArrayList<String>) : ArrayList<Info> = coroutineScope {
val result = mutableListOf<Info>()
launch(Dispatchers.Default) {
for (item in list) {
// Process list item
// Each list item takes about ~ 15-20ms
result.add(info) // add processed info to result
}
}.join() // wait for the task to complete on the background thread
return result // return result
}
这是正确的方法吗?
答案 0 :(得分:2)
您希望将CPU密集型计算的工作卸载到后台线程,以便不会阻塞GUI线程。您无需声明任何暂停函数即可实现此目的。这就是您需要的:
myActivity.launch {
val processedList = withContext(Default) { processList(list) }
... use processedList, you're on the GUI thread here ...
}
上文假设您已将CoroutineScope
接口正确地添加到活动中,如其documentation中所述。
一种更好的做法是将withContext
推入processList
的定义中,这样您就不会犯在主线程上运行它的错误。声明如下:
suspend fun processList(list: List<String>): List<Info> = withContext(Default) {
list.map { it.toInfo() }
}
这假定您已将字符串到信息的逻辑放入
fun String.toInfo(): Info = // whatever it takes
答案 1 :(得分:2)
暂停函数是回调函数的糖。它允许您以线性方式编写带有回调的代码。如果您的函数内部没有回调调用,也没有对另一个挂起的功能的调用,那么使您的函数挂起没有任何意义。除非您希望在后台线程中卸载函数内部的工作(挂起的功能并不总是与后台线程有关),否则,在这种情况下,请使用effects
和适当的调度程序。在这种情况下,您可以选择将函数包装在launch/async
中,也可以使函数挂起并在其中使用launch/async
。