我应该什么时候使我的正常功能暂停功能?
When should I make my normal function suspending function?
使用最新的稳定版 kotlin 协程,我试图使用它来实现我的应用程序的一项功能。但是,我有点困惑。
基本上,我有一个函数可以对项目列表进行一些处理。这需要大约 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
}
开头只有一个挂起修饰符,方法块用coroutineScope { }
包裹起来。
这还重要吗?哪一个更好?如果函数使用协程或 long 运行ning 函数也应标记为挂起函数,我是否应该只将其设为挂起函数?
我很困惑。我看过最近所有关于协程的讨论,但无法弄清楚这一点。
谁能帮我理解一下?
更新:
所以我最终得到了这样的功能。只是为了确保永远不会在主线程上调用该函数。而且调用函数也不必处处记住this需要在后台线程调用。通过这种方式,我可以使调用函数的事情变得抽象:只做被告知的事情,我不关心你想在哪里处理事情。只需处理并给我结果。 所以函数会自行处理它需要 运行 的地方,而不是在调用函数上。
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
}
这是正确的方法吗?
您想将 CPU 密集型计算卸载到后台线程,这样您的 GUI 线程就不会被阻塞。您不必声明任何暂停功能来实现这一点。这就是您所需要的:
myActivity.launch {
val processedList = withContext(Default) { processList(list) }
... use processedList, you're on the GUI thread here ...
}
以上内容假定您已将 CoroutineScope
界面正确添加到 activity,如其 documentation 中所述。
更好的做法是将 withContext
推入 processList
的定义中,这样您就不会在主线程上犯 运行 的错误。声明如下:
suspend fun processList(list: List<String>): List<Info> = withContext(Default) {
list.map { it.toInfo() }
}
这假设您已将字符串到信息逻辑放入
fun String.toInfo(): Info = // whatever it takes
挂起的函数是回调的糖分。它允许您以线性方式编写带有回调的代码。如果你的函数内部没有回调调用,也没有调用另一个挂起的函数,那么我认为让你的函数挂起没有意义。除非你想在后台线程中卸载函数内部的工作(挂起的函数并不总是关于后台线程) - 在这种情况下你使用 launch/async
和适当的调度程序。在这种情况下,您可以选择将您的函数包装在 launch/async
中,或者让您的函数暂停并在其中使用 launch/async
。
使用最新的稳定版 kotlin 协程,我试图使用它来实现我的应用程序的一项功能。但是,我有点困惑。
基本上,我有一个函数可以对项目列表进行一些处理。这需要大约 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
}
开头只有一个挂起修饰符,方法块用coroutineScope { }
包裹起来。
这还重要吗?哪一个更好?如果函数使用协程或 long 运行ning 函数也应标记为挂起函数,我是否应该只将其设为挂起函数?
我很困惑。我看过最近所有关于协程的讨论,但无法弄清楚这一点。
谁能帮我理解一下?
更新:
所以我最终得到了这样的功能。只是为了确保永远不会在主线程上调用该函数。而且调用函数也不必处处记住this需要在后台线程调用。通过这种方式,我可以使调用函数的事情变得抽象:只做被告知的事情,我不关心你想在哪里处理事情。只需处理并给我结果。 所以函数会自行处理它需要 运行 的地方,而不是在调用函数上。
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
}
这是正确的方法吗?
您想将 CPU 密集型计算卸载到后台线程,这样您的 GUI 线程就不会被阻塞。您不必声明任何暂停功能来实现这一点。这就是您所需要的:
myActivity.launch {
val processedList = withContext(Default) { processList(list) }
... use processedList, you're on the GUI thread here ...
}
以上内容假定您已将 CoroutineScope
界面正确添加到 activity,如其 documentation 中所述。
更好的做法是将 withContext
推入 processList
的定义中,这样您就不会在主线程上犯 运行 的错误。声明如下:
suspend fun processList(list: List<String>): List<Info> = withContext(Default) {
list.map { it.toInfo() }
}
这假设您已将字符串到信息逻辑放入
fun String.toInfo(): Info = // whatever it takes
挂起的函数是回调的糖分。它允许您以线性方式编写带有回调的代码。如果你的函数内部没有回调调用,也没有调用另一个挂起的函数,那么我认为让你的函数挂起没有意义。除非你想在后台线程中卸载函数内部的工作(挂起的函数并不总是关于后台线程) - 在这种情况下你使用 launch/async
和适当的调度程序。在这种情况下,您可以选择将您的函数包装在 launch/async
中,或者让您的函数暂停并在其中使用 launch/async
。