我下面有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/blocking-threads-suspending-coroutines-d33e11bf4761
答案 0 :(得分:0)
1和2相同。仅当它与协程一起执行某些操作时,才需要在函数中添加suspend
修饰符。
第一种情况和第三种情况之间的区别:
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()
}
答案 1 :(得分:0)
通过向函数添加suspend
修饰符,可以允许该函数使用另一个挂起函数。例如,如果runMe()
函数将使用暂停delay,则使该函数可暂停是合理的。请参阅Your first coroutine文档部分。
挂起函数与普通函数的另一个主要区别是挂起函数are cancellable。让我们看一下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活动)将加载数据以显示它。如果活动是在加载第二部分数据之前关闭的,则加载第二部分是浪费的。但是,由于loadSecondPartOfData()
函数正在挂起,因此它会检查范围是否处于活动状态,如果范围处于非活动状态,则该函数将不会执行。
还要注意函数如何使用withContext(Dispatchers.IO)
。从viewModelScope.launch
调用函数,默认情况下使用Dispatchers.Main
(UI线程),但是从UI线程调用函数是安全的,因为执行上下文是由函数显式选择的。当您在调用函数时不必担心当前线程时,这是编写挂起函数的正确方法。这是关于你的第三个问题。
在您的示例中,第一个代码片段可以使用,但是在真实的应用程序中,事情通常会变得有些复杂。