【Kotlin 协程】协程启动 ⑤ ( 协程作用域构建器 | runBlocking 函数 | coroutineScope 函数 | supervisorScope 函数 )

2023-03-30 18:07:27 浏览数 (1)

文章目录

  • 一、结构化并发
  • 二、协程作用域构建器 ( runBlocking 函数 | coroutineScope 函数 )
  • 二、协程作用域构建器 ( coroutineScope 函数 | supervisorScope 函数 )
    • 1、协程作用域构建器概念
    • 2、coroutineScope 协程作用域构建器 示例
    • 3、supervisorScope 协程作用域构建器 示例

一、结构化并发


  • 【Kotlin 协程】协程底层实现 ② ( 协程调度器 | 协程任务泄漏 | 结构化并发 )
  • 【Kotlin 协程】协程底层实现 ③ ( 结构化并发 | MainScope 作用域 | 取消协程作用域 | Activity 实现 CoroutineScope 协程作用域接口 )
  • 【Kotlin 协程】协程底层实现 ④ ( 结构化并发 | viewModelScope 作用域示例 )

博客中介绍了 结构化并发 ;

结构化并发的作用 : 协程任务 运行时 , 必须指定其 CoroutineScope 协程作用域 , 其会 追踪所有的 协程任务 , CoroutineScope 协程作用域 可以 取消 所有由其启动的协程任务 ;

结构化并发 使用场景 :

  • 协程任务取消 : 在不需要协程任务的时候 , 取消协程任务 ;
  • 追踪协程任务 : 追踪正在执行的协程任务 ;
  • 发出错误信号 : 如果 协程任务执行失败 , 发出错误信号 , 表明执行任务出错 ;

二、协程作用域构建器 ( runBlocking 函数 | coroutineScope 函数 )


结构化并发 通过 协程作用域 CoroutineScope 管理协程任务 ;

协程作用域 构建器 是 结构化并发 的重要组成部分 ;

常用的 协程作用域构建器 有 coroutineScope 和 runBlocking ;

  • runBlocking 是 普通函数 , 可以在 普通的代码位置使用 , 将 主线程 或 子线程 包装成 协程体 , 在该协程中执行 协程任务 , 会 阻塞当前的线程 ; 函数原型如下 :
代码语言:javascript复制
public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T 
  • coroutineScope 是 挂起函数 , 只能在 协程体 中使用 , 该协程会在另外的独立的线程执行 协程任务 , 不会干扰当前启动协程的线程 ; 函数原型如下 :
代码语言:javascript复制
public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R 

共同点 : 这两个 协程作用域构建器 构建的协程 都会等待 协程体 中的所有 协程任务 和 子协程 执行完毕 ;

代码示例 : 在下面的代码中 , runBlocking 可以在普通的函数中执行 , 将主线程包装成了协程体 ; 但是 coroutineScope 函数 由于是 挂起函数 , 只能在 协程体 中使用 ; 该 coroutineScope 协程作用域 将 子协程 job0 和 job1 包裹起来 , coroutineScope 作用域需要等待 两个子协程执行完毕 , 该作用域才算执行完毕 ;

代码语言:javascript复制
package kim.hsl.coroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*

class MainActivity : AppCompatActivity(){
    val TAG = "MainActivity"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            // 调用 runBlocking 函数 , 可以将 主线程 包装成 协程

            coroutineScope {
                // 该 coroutineScope 协程作用域 将 子协程 job0 和 job1 包裹起来
                // coroutineScope 作用域需要等待 两个子协程执行完毕 , 该作用域才算执行完毕

                val job0 = launch {
                    delay(2000)
                    Log.i(TAG, "job0 协程执行完毕")
                }

                val job1 = async {
                    delay(2000)
                    Log.i(TAG, "job1 协程执行完毕")
                    "Hello" // 返回一个字符串
                }
            }
        }
    }
}

二、协程作用域构建器 ( coroutineScope 函数 | supervisorScope 函数 )


1、协程作用域构建器概念

coroutineScope 函数 构建的 协程作用域 , 如果有一个 子协程 执行失败 , 则其它 所有的子协程会被取消 ; 函数原型如下 :

代码语言:javascript复制
public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R

supervisorScope 函数 构建的 协程作用域 , 如果有一个 子协程 执行失败 , 其它子协程继续执行 , 不会受到执行失败的子协程影响 ; 函数原型如下 :

代码语言:javascript复制
public suspend fun <R> supervisorScope(block: suspend CoroutineScope.() -> R): R 

2、coroutineScope 协程作用域构建器 示例

coroutineScope 函数 构建的 协程作用域 代码示例 : 并发执行两个协程 , 取消其中一个协程 , 另外一个协程也会自动取消 ;

代码语言:javascript复制
package kim.hsl.coroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*

class MainActivity : AppCompatActivity(){
    val TAG = "MainActivity"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            // 调用 runBlocking 函数 , 可以将 主线程 包装成 协程

            coroutineScope {
                // 该 coroutineScope 协程作用域 将 子协程 job0 和 job1 包裹起来
                // coroutineScope 作用域需要等待 两个子协程执行完毕 , 该作用域才算执行完毕

                // coroutineScope 函数 构建的 协程作用域 ,
                // 如果有一个 子协程 执行失败 , 则其它 所有的子协程会被取消 ;

                val job0 = launch {
                    Log.i(TAG, "job0 协程开始执行")
                    delay(2000)
                    Log.i(TAG, "job0 协程执行完毕")
                }

                val job1 = async {
                    Log.i(TAG, "job1 协程开始执行")
                    delay(1000)

                    // 抛出异常 , job1 执行取消
                    Log.i(TAG, "job1 协程 抛出异常取消执行")
                    throw java.lang.IllegalArgumentException()

                    Log.i(TAG, "job1 协程执行完毕")
                    "Hello" // 返回一个字符串
                }
            }
        }
    }
}

执行结果 : 在 job1 协程抛出异常后 , 未执行完毕的 job0 协程也被取消 ;

3、supervisorScope 协程作用域构建器 示例

supervisorScope 函数 构建的 协程作用域 代码示例 : 并发执行两个协程 , 取消其中一个协程 , 另外一个协程不会受到影响 , 仍然执行完毕 ;

代码语言:javascript复制
package kim.hsl.coroutine

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*

class MainActivity : AppCompatActivity(){
    val TAG = "MainActivity"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        runBlocking {
            // 调用 runBlocking 函数 , 可以将 主线程 包装成 协程

            supervisorScope {
                // supervisorScope 函数 构建的 协程作用域 ,
                // 如果有一个 子协程 执行失败 ,
                // 其它子协程继续执行 , 不会受到执行失败的子协程影响 ;

                val job0 = launch {
                    Log.i(TAG, "job0 协程开始执行")
                    delay(2000)
                    Log.i(TAG, "job0 协程执行完毕")
                }

                val job1 = async {
                    Log.i(TAG, "job1 协程开始执行")
                    delay(1000)

                    // 抛出异常 , job1 执行取消
                    Log.i(TAG, "job1 协程 抛出异常取消执行")
                    throw java.lang.IllegalArgumentException()

                    Log.i(TAG, "job1 协程执行完毕")
                    "Hello" // 返回一个字符串
                }
            }
        }
    }
}

执行结果 :

0 人点赞