android CoroutineScope与暂停功能

8ftvxx2r  于 2023-02-02  发布在  Android
关注(0)|答案(2)|浏览(203)

我有点困惑,我知道如果一个函数要使用协程,它应该声明为suspend。例如:

private suspend fun doSomething() {  
      withContext(Dispatchers.IO) {      
   //do something 
 } }

而且我还知道有这样一种方法可以使用协程而不需要挂起函数。

private fun doSomething1() {      
    CoroutineScope(Dispatchers.IO).launch { 
          //do something  
} }

这两个函数有什么区别?什么时候用第一个例子,什么时候用第二个例子?

0h4hbjxa

0h4hbjxa1#

这两种功能有什么区别?
两者之间有2个主要区别:

  • 用法不同:suspend "感觉"同步,而launch显式异步
  • 第二个函数破坏了结构化并发,不应该这样编写

让我详细说明一下。
从使用Angular 来看,suspend函数似乎是同步的:当您调用它时,下一行代码仅在函数完成时执行(就像任何其他常规函数一样)。这使得推理变得容易。你甚至可以将suspend函数的返回值赋给一个变量,然后继续你的生活,就好像这个函数不是suspend一样。也就是说,当你已经在一个suspend的上下文中时,你必须用一个显式的协程构建器(比如launchasyncrunBlocking)来启动"根"协程。
当使用launch时,您显式启动了一个异步任务,因此launch之后的代码将与launch内部的代码并发运行。因此,当调用doSomething1()时,它之后的代码将与launch内部的代码并发运行。然而,从API的Angular 来看,这个函数是否会启动一个比它更有效的任务还不清楚。这也与你不应该创建这样的"自由"协同程序作用域的事实有关。我将在下面详细说明。
什么时候用第一个例子,什么时候用第二个例子?
尽可能多地使用suspend函数来简化事情。大多数时候,你不需要启动比函数调用更有效的任务,所以这是非常好的。你仍然可以通过使用coroutineScope { ... }启动一些协程来并发地 * 在你的suspend函数内 * 做一些工作。这不需要外部提供的作用域,从调用者的Angular 来看,所有的计算都将发生在suspend函数调用中,因为coroutineScope {}将等待子协程完成后再返回。
这里使用launch的函数表现很差,你不应该这样写:

  • CoroutineScope不应当场创建并任其自生自灭,应保留一个句柄并在适当时取消
  • 如果在调用这个函数时您已经处于挂起状态,那么现有的协程上下文和作业将被忽略

为了避免这些问题,您可以通过将CoroutineScope设置为接收器而不是立即创建一个接收器来使API显式化:

private fun CoroutineScope.doSomething1() {      
    launch(Dispatchers.IO) { 
          //do something  
    }
}

但是,只有当函数的本质是启动一些在函数返回后仍将继续的东西时,才使用这种方法。

5gfr0r5j

5gfr0r5j2#

最简单的答案是suspend函数是一个可以在CoroutineScope中执行的块。所以它不是第一个例子和第二个例子。通过组合这些块,您可以启动自己的作用域,并使用不同的上下文执行suspend函数。

private suspend fun doSomething() {  
  withContext(Dispatchers.IO){  
    // task executed in io thread
  }
}
    
private suspend fun doSomethingUI() {  
  withContext(Dispatchers.Main) {      
     // task executed in ui thread
  } 
}
    
private fun ioOperation() {      
   CoroutineScope(Dispatchers.IO).launch { 
     doSomething()
     doSomethingUI()
   } 
}

编辑:这只是一个简单的基本示例,它没有处理协程作用域的正确生命周期,不应该直接使用。

相关问题