3.4-CoroutineScope/CoroutineContext:coroutineScope() 和 supervisorScope()

文章目录

  • coroutineScope()
  • supervisorScope()
  • 总结

coroutineScope()

coroutineScope() 和我们创建协程时的 CoroutineScope 名字是相同的,实际上它们也确实有所关联,为了方便理解我们先说下 coroutineScope() 是怎样的效果。

我们在使用 coroutineScope() 时 IDE 会有提示官方文档:

在这里插入图片描述

创建一个 CoroutineScope 然后在这个 scope 里面执行它的 block 代码块里的代码,这个 CoroutineScope 会继承当前的 coroutineContext,以及用当前的 Job 来作为内部的父 Job。

按照上面的解释,可以发现 coroutineScope() 也是会创建一个子协程,和用 launch 创建子协程很像:

fun main() = runBlocking {val scope = CoroutineScope(EmptyCoroutineContext)scope.launch {coroutineScope {// block 代码块的 this 是一个新的 CoroutineScope// 代码块里的代码会在新的 CoroutineScope 里执行// 在这个代码块使用的 coroutineContext 和外面 scope.launch 代码块的 coroutineContext 是一样的// 不同的地方只有 coroutineScope() 创建了一个子 Job }launch {// 子协程的也是一个新的 CoroutineScope// 也是一个子 Job}}delay(10000)
}

coroutineScope() 和 launch 有区别的地方

  • coroutineScope() 不能像 launch 一样定制 CoroutineContext
fun main() = runBlocking {val scope = CoroutineScope(EmptyCoroutineContext)scope.launch {// 不能指定 CoroutineContext,比如指定运行线程 ContinuationInterceptorcoroutineScope {}// 能指定 CoroutineContextlaunch(Dispatchers.IO) {}}delay(10000)
}
  • coroutineScope() 是一个挂起函数,运行时是串行执行的,会等待它内部的代码块(包括它里面的子协程)都执行完成才返回继续后续的代码;launch 启动协程是并行执行的,启动协程后就继续执行后续的代码
fun main() = runBlocking {val scope = CoroutineScope(EmptyCoroutineContext)scope.launch {// 挂起函数,等待代码块的代码执行完后才继续往后执行val startTime = System.currentTimeMillis()coroutineScope {delay(1000)println("Duration within coroutineScope: ${System.currentTimeMillis() - startTime}")}println("Duration of coroutineScope: ${System.currentTimeMillis() - startTime}")}delay(10000)	
}输出结果:
Duration within coroutineScope: 1006
Duration of coroutineScope: 1007 // 等待执行完后才执行后续代码fun main() = runBlocking {val scope = CoroutineScope(EmptyCoroutineContext)scope.launch {// 启动协程,launch 执行后就继续往后执行不等待val startTime = System.currentTimeMillis()launch {delay(1000)println("Duration within launch: ${System.currentTimeMillis() - startTime}")				}println("Duration of launch: ${System.currentTimeMillis() - startTime}")			}delay(10000)	
}输出结果:
Duration of launch: 0 // launch 调用完就继续执行后续代码
Duration within launch: 1010 
  • coroutineScope() 有返回值,launch 没有返回值
fun main() = runBlocking {val scope = CoroutineScope(EmptyCoroutineContext)scope.launch {val result = coroutineScope {val deferred1 = async { "Hello" }val deferred2 = async { "coroutine!" }"${defferred1.await()} ${deferred2.await()}"}println(result)}delay(10000)
}输出结果:Hello coroutine!

需要注意的是,我们用 coroutineScope() 和 launch 对比并不是想着 [什么时候用 coroutineScope() 替换 launch 使用],只是因为它们内部的工作原理有很大的相似之处,但它们的应用场景是完全不同的

实际上最适合和 coroutineScope() 做对比的是,在协程内部啥都不用

fun main() = runBlocking {val scope = CoroutineScope(EmptyCoroutineContext)scope.launch {// 这两者没啥区别,这么使用肯定优先选不用 coroutineScope() 执行的函数someFunc()coroutineScope {someFunc()	}}delay(10000)	
}

如果我们在协程调用一个函数 someFunc(),这时候直接在协程调用和用 coroutineScope() 包着调用函数相比,直接调用 someFunc() 函数会更合理。

但如果 someFunc() 是一个挂起函数,而且又想在挂起函数启动协程时,coroutineScope() 就派上用场了:

fun main() = runBlocking {val scope = CoroutineScope(EmptyCoroutineContext)scope.launch {someFunc()}delay(10000)	
}// 是一个挂起函数,挂起函数是没有 CoroutineScope 的
// 这里就可以用 coroutineScope() 给挂起函数提供一个 CoroutineScope 可以启动协程的环境
private suspend fun someFunc() = coroutineScope {launch {}
}

coroutineScope() 的第一个使用场景是:当我们想在挂起函数里启动协程但又没有启动协程的环境时,就用 coroutineScope() 提供 CoroutineScope 的环境

coroutineScope() 的第二个使用场景是: coroutineScope() 可以用来封装完整的功能逻辑,在抛出异常时正确捕获异常能让整个外部协程继续正常工作而不会导致整个协程树崩溃

fun main() = runBlocking {val scope = CoroutineScope(EmptyCoroutineContext)scope.launch {// 正确处理异常,让整个协程树能正常运行val result = try {coroutineScope {val deferred1 = async { "Hello" }val deferred2: Deferred<String> = async { throw RuntimeException("Error!") }"${defferred1.await()} ${deferred2.await()}"}} catch (e: Exception) {e.message}println(result)}delay(10000)
}输出结果:Error!

supervisorScope()

supervisorScope() 和 coroutineScope() 在功能上是相同的,不同的是 supervisorScope() 创建子协程是一个类似于 SupervisorJob 的子 Job。关于 SupervisorJob 可以查看之前写的文章 2.4-结构化并发:协程的结构化异常管理 具体了解。

但大多数时候挂起函数里启动的各个子协程通常对于挂起函数的总流程都是有用的,在 coroutineScope() 抛异常通常来说整个挂起函数就失去价值了,它就应该坏掉抛异常。所以 supervisorScope() 的适用场景并不多

总结

coroutineScope() 会创建一个子协程,和使用 launch 创建子协程很像。

我们用 coroutineScope() 和 launch 对比并不是想着 [什么时候用 coroutineScope() 替换 launch 使用],只是因为它们内部的工作原理有很大的相似之处,但它们的应用场景是完全不同的

coroutineScope() 和 launch 有以下不同

  • coroutineScope() 不能像 launch 一样定制 CoroutineContext

  • coroutineScope() 是一个挂起函数,运行时是串行执行的;launch 启动协程是并行执行的

  • coroutineScope() 有返回值,launch 没有返回值

coroutineScope() 的使用场景主要有以下两个

  • 在挂起函数提供 CoroutineScope 启动协程的环境

  • 封装完整的功能逻辑

supervisorScope() 和 coroutineScope() 在功能上是相同的,不同的是 supervisorScope() 创建子协程是一个类似于 SupervisorJob 的子 Job。使用场景并不多,可以根据具体场景选择使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/408402.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络常见面试题总结

文章目录 1 计算机网络基础1.1 网络分层模型1.1.1 OSI 七层模型是什么&#xff1f;每一层的作用是什么&#xff1f;1.1.2 TCP/IP 四层模型是什么&#xff1f;每一层的作用是什么&#xff1f;1.1.3 为什么网络要分层&#xff1f; 1.2 常见网络协议1.2.1 应用层有哪些常见的协议&…

MySQL主从复制之GTID模式

目录 1 MySQL 主从复制 GTID 模式介绍 2 传统复制模式与GTID复制模式的区别 3 GTID模式核心参数 4 GTID 实现自动复制原理 4.1 GTID基本概念 4.2 GTID复制流程 5 GTID 实现自动定位 5.1 配置 my.cnf 5.2 配置 SLAVE 实现自动定位 5.3 测试 6 GTID 模式 故障转移的方法流程 6.1…

记一次NULL与空字符串导致的分组后产生重复数据

目录 一&#xff0c;场景说明二&#xff0c;实现功能三&#xff0c;修改原实现方法四&#xff0c;说明 一&#xff0c;场景说明 想实现这样一个功能&#xff0c;统计人员信息中不同性别的人的总工资。 实现方式&#xff1a;将数据group by 分组后累加。 二&#xff0c;实现功…

SpringMVC核心机制环境搭建

文章目录 1.SpringMVC执行流程1.基础流程图2.详细流程图 2.安装Tomcat1.下载2.解压到任意目录即可3.IDEA配置Tomcat1.配置Deloyment2.配置Server 3.创建maven项目1.创建sun-springmvc模块&#xff08;webapp&#xff09;2.查看是否被父模块管理3.pom.xml引入依赖4.目录5.SunDis…

npm阿里云制品仓库

配置 配置仓库地址&#xff0c;可以再在仓库指南看到 npm config set registryxxxxx#登录&#xff0c;帐户密码可以在仓库指南看到 npm login注意&#xff1a;npm>9的版本npm login目前有问题 verbose web login not supported, trying couch&#xff0c;暂时没试验到解决…

C语言函数递归

前言与概述 本文章将通过多个代码并赋予图示&#xff0c;详细讲解C语言函数递归的定义和函数递归的运算过程。 函数递归定义 程序调用自身的编程技巧称为递归。递归作为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法。它…

LLM agentic模式之规划能力(planning)

文章目录 任务分解分解优先方法交替分解方法 多计划选择外部规划器辅助规划反思和改进记忆增强规划评估 2024年2月的综述《 Understanding the planning of LLM agents: A survey》提供了基于LLM的的agent的规划(planning)能力的系统视角&#xff0c;总结了近年来提高规划能力…

EmguCV学习笔记 VB.Net 6.4 霍夫变换

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

基于x86 平台opencv的图像采集和seetaface6的人脸朝向姿态估计功能

目录 一、概述二、环境要求2.1 硬件环境2.2 软件环境三、开发流程3.1 编写测试3.2 配置资源文件3.2 验证功能一、概述 本文档是针对x86 平台opencv的图像采集和seetaface6的人脸朝向姿态估计功能,opencv通过摄像头采集视频图像,将采集的视频图像送给seetaface6的人脸朝向姿态…

Telnet不止于端口测试:探索经典工具的多样化应用

文章目录 Telnet详解与实用指南1. 引言2. Telnet 的安装和启动2.1 在 Windows 上安装 Telnet2.2 在 Linux 上安装 Telnet2.3 在 macOS 上使用 Telnet 3. Telnet 的基本命令与操作3.1 远程登录3.2 测试端口连通性3.3 调试网络服务3.4 网络协议调试3.5 简单的文件传输 4. Telnet …

sklearn中的线性回归

多元线性回归 指的 是一个样本 有多个特征的 线性回归问题。 w 被统称为 模型的 参数&#xff0c;其中 w0 被称为截距&#xff08;intercept&#xff09;&#xff0c;w1~wn 被称为 回归系数&#xff08;regression coefficient&#xff09;。这个表达式和 yazb 是同样的…

Web前端性能优化合集

简介 自互联网兴起以来&#xff0c;从最初的静态网页到如今的动态交互、单页应用&#xff08;SPA&#xff09;、PWA&#xff08;Progressive Web Apps&#xff09;等&#xff0c;互联网技术正在飞速发展&#xff0c;随着用户体验成为核心竞争力之一&#xff0c;前端性能直接影…

【Midjourney】Midjourney全面开放网站版,所有用户每天可免费生成25次

Midjourney一直作为AI文生图领域的龙头老大&#xff0c;最近对面对市场上日益增长的竞争压力&#xff0c;尤其是来自 Flux 的挑战&#xff0c;终于向所有用户开放官方网站。尽管还处于早期阶段&#xff0c;但为了吸引更多用户体验&#xff0c;它暂时是完全免费的。 下面是Midj…

什么是d3dx9_42.dll?如何将丢失的d3dx9_42.dll进行修复呢?

d3dx9_42.dll文件丢失什么情况&#xff1f;如何将丢失的d3dx9_42.dll进行修复呢&#xff1f;d3dx9_42.dll又是什么文件&#xff1f;d3dx9_42.dll 文件是一个由 Microsoft Corporation 开发的部分&#xff0c;属于 Microsoft DirectX for Windows 的一组庞大库集合中的一个。Dir…

Android系统架构

文章目录 Android系统架构Android四层架构01.Linux内核层02.系统运行库层03.应用框架层04.应用层 Android应用开发特色01.四大组件02.丰富的系统控件03. SQLite数据库04.强大的多媒体05.地理位置定位 Android系统架构 为了让你能够更好地理解Android系统是怎么工作的&#xff…

HashMap 的实现原理

说一下 HashMap 的实现原理&#xff1f; JDK1.7 HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元&#xff0c;每一个Entry包含一个key-value键值对。&#xff08;其实所谓Map其实就是保存了两个对象之间的映射关系的一种集合&#xff09;&#xff0c;其中Key 和…

PDPS软件 那智机器人 (丰田版)离线程序导出处理

在PDPS仿真软件中导出的那智机器人离线程序&#xff0c;一般是无法直接给TFD控制装置-那智机器人&#xff08;丰田式样版&#xff09;导入及识别使用。因此要对导出的程序进行转换编译处理&#xff0c;才能给TFD那智机器人&#xff08;丰田式样版&#xff09;导入离线程序。以下…

Java共享内容通信 VS Golang通信共享内存

接触的编程语言从C到Java再到现在Go&#xff0c;每个语言都有其独有特性&#xff0c;也具备共通之处。 最近在学习并发编程的时候&#xff0c;发现一个很有意思的点&#xff1a;Java基于共享共享内存通信&#xff0c;而Golang则是通过通信共享内存。为什么&#xff1f;下面我们…

自定义@ResponseBody以及SpringMVC总结

文章目录 1.需求分析2.目录3.自定义ResponseBody注解4.MonsterController.java5.Monster.java 实现序列化接口6.引入jackson7.Adapter.java 如果有ResponseBody注解就返回json8.测试9.SpringMVC执行流程 1.需求分析 2.目录 3.自定义ResponseBody注解 package com.sunxiansheng…

简单实现进度条效果(vue2)

如果用echarts或者其他图表来写个进度条有点大材小用&#xff0c;所以直接简单html、js写一下就可以&#xff1b; 以下代码基于vue2&#xff0c; 部分代码来自国内直连GPT/Claude镜像站 <template><div class"progress-container"><div class"p…