我下面有3个片段
fun main() = CoroutineScope(Dispatchers.IO).launch { runMe() }
fun rumMe() = doSomething()
fun main() = CoroutineScope(Dispatchers.IO).launch { runMe() }
suspend fun rumMe() = doSomething()
fun main() = CoroutineScope(Dispatchers.IO).launch { runMe() }
suspend fun rumMe() = withContext(Dispatchers.Default) { doSomething() }
我看到它们在与Main不同的线程中启动,并且异步运行而不阻塞主线程。
我想知道它们有什么不同?如果它们都一样,那么1最好。如果没有,我什么时候应该使用2或3?
我试着读这个,但不能清楚地读出来https://medium.com/@elizarov/阻塞线程挂起协程d33e11bf4761
1和2是相同的。只有当函数使用协程执行某些操作时,您才必须将挂起
修饰符添加到您的函数中。
第一种情况与第三种情况的区别:
fun main() = CoroutineScope(Dispatchers.IO).launch {
// io thead executor
runMe()
}
// still io thread executor
fun rumMe() = doSomething()
fun main() = CoroutineScope(Dispatchers.IO).launch {
// io thead executor
runMe()
}
suspend fun rumMe() = withContext(Dispatchers.Default) {
// default/cpu thead executor
doSomething()
}
通过向函数添加挂起
修饰符,您允许该函数使用另一个挂起函数。例如,如果runMe()
函数将使用挂起延迟,则使该函数可挂起是合理的。请参阅您的第一个协程留档部分。
挂起函数与普通函数的另一个主要区别是挂起函数是可取消的。让我们看一下Android示例:
class MyViewModel : BaseViewModel() {
init {
viewModelScope.launch {
val firstPart = loadFirstPartOfData()
val secondPart = loadSecondPartOfData(firstPart)
...
}
}
suspend loadFirstPartOfData() = withContext(Dispatchers.IO) { ... }
suspend loadSecondPartOfData(firstPartOfData: FirstPartOfData) {
// some UI thread safe calculations
return withContext(Dispatchers.IO) {
// network request here
}
}
}
想象一下,视图(Android Activity)加载数据来显示它。如果在加载第二部分数据之前关闭Activity,则加载第二部分是浪费的。但是,由于loadBydPartOfData()
函数处于挂起状态,它会检查作用域是否处于活动状态,如果作用域不处于活动状态,则不会执行该函数。
还要注意函数是如何使用with Context(Dispatchers.IO)
的。函数是从viewModelScope.启动
调用的,默认情况下使用Dispatcher. Main
(UI线程),但是从线程调用函数是安全UI,因为执行上下文是由函数显式选择的。这是编写挂起函数的正确方法,当你调用函数时不必担心当前线程。这是关于你的第三个问题。
在您的示例中,第一个片段将起作用,但在真正的应用程序中,像往常一样,事情变得有点复杂。