协程范围,挂起和withContext查询

时间:2019-08-15 08:58:13

标签: multithreading kotlin coroutine kotlin-coroutines

我下面有3个片段

  1. 启动范围
    fun main() = CoroutineScope(Dispatchers.IO).launch { runMe() }
    fun rumMe() = doSomething()
  1. 在暂停状态下启动范围
    fun main() = CoroutineScope(Dispatchers.IO).launch { runMe() }
    suspend fun rumMe() = doSomething()
  1. 使用suspend和withContext启动范围
    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

2 个答案:

答案 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线程调用函数是安全的,因为执行上下文是由函数显式选择的。当您在调用函数时不必担心当前线程时,这是编写挂起函数的正确方法。这是关于你的第三个问题。

在您的示例中,第一个代码片段可以使用,但是在真实的应用程序中,事情通常会变得有些复杂。