zl程序教程

您现在的位置是:首页 >  后端

当前栏目

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

Kotlin 函数 启动 构建 作用域 协程
2023-09-14 09:07:26 时间





一、结构化并发



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

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

结构化并发 使用场景 :

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




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



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

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


常用的 协程作用域构建器 coroutineScoperunBlocking ;

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

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


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

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 函数 构建的 协程作用域 , 如果有一个 子协程 执行失败 , 则其它 所有的子协程会被取消 ; 函数原型如下 :

public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R

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

public suspend fun <R> supervisorScope(block: suspend CoroutineScope.() -> R): R 

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


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

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

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" // 返回一个字符串
                }
            }
        }
    }
}

执行结果 :

在这里插入图片描述