Kotlin 协程 CoroutineScope

协程定义:

19年官方是这样说的:协程是轻量级的线程,协程就是 Kotlin 提供的一套线程封装的 API;

现在官方是这样说的:协程是一种并发设计模式;

协程作用:

1.处理耗时任务;

2.保证主线程的安全;

3.简化异步执行的代码,解决并发问题,让「协作式多任务」实现起来更加方便。

使用协程,同样可以像 Rx 那样有效地消除回调地狱,不过无论是设计理念,还是代码风格,两者是有很大区别的,协程在写法上和普通的顺序代码类似。

协程特点:

轻量:您可以在单个线程上运行多个协程,因为协程支持挂起,不会使正在运行协程的线程阻塞。挂起比阻塞节省内存,且支持多个并行操作。

内存泄漏更少:使用结构化并发机制在一个作用域内执行多项操作。

内置取消支持:取消功能会自动通过正在运行的协程层次结构传播。

协程使用: 

1.lauch

lauch用于在协程作用域中异步启动一个新的协程,调用该方法不会阻塞线程。

CoroutineScope(Dispatchers.IO).launch {
	// 启动一个非阻塞线程的协程
}

2.suspend

suspend是协程的关键字,每一个被suspend修饰的方法都必须在另一个suspend函数或者Coroutine协程程序中进行调用。 

3.coroutineScope

coroutineScope是一个挂起函数,每一个被suspend修饰的方法都必须在另一个suspend函数或者Coroutine协程程序中进行调用。

CoroutineScope(Dispatchers.IO).launch {
	coroutineScope {
		// 启动一个非阻塞线程的协程
	}
}

runBlocking {
	coroutineScope {
		// 启动一个非阻塞线程的协程
	}
}

4.runBlocking

runBlocking会阻塞当前线程,而coroutineScope不会阻塞所在的线程,它会挂起所在的协程直至其内部任务(包括子协程)执行完成。

runBlocking {
	// 启动一个阻塞线程的协程
}

5.dispatcher

dispatcher 协程调度器,可以控制协程代码块在UI线程还是子线程中执行;

6.async

1)在概念上,async 就类似于 launch。它启动了一个单独的协程与其它所有的协程一起并发的工作。不同之处在于 launch 返回一个 Job 并且不附带任何结果值,而 async 返回一个 Deferred接口指向的对象,使用 Deferred.await()在一个延期的值上得到它的最终结果,同时Deferred 也是一个 Job,所以如果需要的话,可以使用Deferred.cancel()取消它。

CoroutineScope(Dispatchers.IO).launch {
	val api1Deferred = async { api1() }
	val api2Deferred = async { api2() }
	val api3Deferred = async { api3() }
	println("api*****1")
	val result1 = api1Deferred.await()
    println("api*****2")
}

suspend fun api1(): String {
	delay(2500) // 模拟耗时操作
	println("api1")
	return "api1"
}

suspend fun api2(): String {
	delay(2000) // 模拟耗时操作
	println("api2")
	return "api2"
}

suspend fun api3(): String {
	delay(1500) // 模拟耗时操作
	println("api3")
	return "api3"
}

输出结果: 

结论:

async启动的所有协程是一起并发工作的,async不是挂起函数,所以不会挂起launch创建的协程,所以先输出api*****1,再api3、api2、api1,但执行到api1Deferred.await()时,会挂起协程,等待async { api1() }执行完返回结果后,再执行协程后续的函数,所以最后输出api*****2,因为await()是挂起函数。

public suspend fun await(): T

2)案例:有4个耗时方法,方法名api1,api2,api3,api4;要求方法api1先执行,返回String "api1",然后将结果"api1"作为参数,并发执行方法api2和方法api3,由于api3 delay(1500),api2 delay(2000),所以api3会先执行完并输出结果,然后api2再执行完并输出结果,最后将结果"api2",api3"作为参数,执行方法api4。

CoroutineScope(Dispatchers.IO).launch {
	val api1Deferred = async { api1() }
	println("api*****1")
	val result1 = api1Deferred.await()
	println("api1:$result1") // 等待 api1 方法执行完成并输出结果
	val api2Deferred = async { api2(result1) }
	val api3Deferred = async { api3(result1) }
	val result2 = api2Deferred.await()
	println("api2:$result2")
	val result3 = api3Deferred.await()
	println("api3:$result3")
	println(api4(result2, result3))
}

suspend fun api1(): String {
	delay(3000) // 模拟耗时操作
	println("api1")
	return "api1"
}

suspend fun api2(v: String): String {
	delay(2000) // 模拟耗时操作
	println("api2")
	return "api2:$v"
}

suspend fun api3(v: String): String {
	delay(1500) // 模拟耗时操作
	println("api3")
	return "api3:$v"
}

suspend fun api4(v: String, v2: String): String {
	delay(500) // 模拟耗时操作
	return "api4:$v$v2"
}

输出结果:  

注:async是并行的,如果使用await()的话,await()是挂起函数,会挂起协程,等待async { api1() }执行完返回结果后,再执行协程后续的函数。

7. withContext

withContext 与 async 都可以返回耗时任务的执行结果。多个 withContext 任务是串行(顺序执行)的, 且withContext 可直接返回耗时任务的结果。 而多个 async 任务是并行的。

public suspend fun <T> withContext()

因为withContext()是挂起函数,执行后,会挂起协程,等待withContext内部函数执行完后,再执行withContext函数后面的函数。

CoroutineScope(Dispatchers.IO).launch {
	val result1 = withContext(Dispatchers.IO) {
		api1()
	}
	println("api*****1")
	println("api1:$result1") // 等待 api1 方法执行完成并输出结果
	val result2 = withContext(Dispatchers.IO) {
		api2(result1)
	}
	println("api2:$result2")
	val result3 = withContext(Dispatchers.IO) {
		api3(result1)
	}
	println("api3:$result3")
	val result4 = withContext(Dispatchers.IO) {
		api4(result2, result3)
	}
	println(result4)
}

suspend fun api1(): String {
	delay(3000) // 模拟耗时操作
	println("api1")
	return "api1"
}

suspend fun api2(v: String): String {
	delay(2000) // 模拟耗时操作
	println("api2")
	return "api2:$v"
}

suspend fun api3(v: String): String {
	delay(1500) // 模拟耗时操作
	println("api3")
	return "api3:$v"
}

suspend fun api4(v: String, v2: String): String {
	delay(500) // 模拟耗时操作
	return "api4:$v$v2"
}

输出结果:   

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kotlin 新版本 1.9.0重要更新预览

释放 Kotlin 新版本 1.9.0 的强大功能 1. Kotlin K2编译器用于多平台 对K2编译器进行了进一步的改进&#xff0c;使其更加稳定。K2编译器针对JVM目标现已进入Beta版本&#xff0c;并且也可以在多平台项目中使用。 您可以通过将K2配置添加到项目的gradle.properties中&#x…

九、数据结构——顺序队列中的循环队列

目录 一、循环队列的定义 二、循环队列的实现 三、循环队列的基本操作 ①初始化 ②判空 ③判满 ④入队 ⑤出队 ⑥获取长度 ⑦打印 四、循环队列的应用 五、全部代码 数据结构中的循环队列 在数据结构中&#xff0c;队列&#xff08;Queue&#xff09;是一种常见的线性数据结…

pytest+allure运行出现乱码的解决方法

pytestallure运行出现乱码的解决方法 报错截图&#xff1a; 这里的截图摘自 悟翠人生 小伙伴的https://blog.csdn.net/weixin_45435918/article/details/107601721一文。 这是因为没有安装allure运行环境或者没有配置allure的环境变量导致&#xff0c;解决方案&#xff1a; 1…

Vue移动端项目--瑞幸咖啡重构优化

来了客官&#xff0c;好久不见&#xff01; 从年初开始&#xff0c;就有个想法&#xff0c;想着把之前做过的项目重新整理一下。毕竟今时不同往日&#xff0c;从现在的角度去看曾经做过的项目&#xff0c;倒是觉得有很多稚嫩的地方。毕竟无论做什么都是熟能生巧&#xff0c;由浅…

深度学习推理和训练

优化和泛化 深度学习的根本问题是优化和泛化之间的对立。 • 优化&#xff08;optimization&#xff09;是指调节模型以在 训练数据 上得到最佳性能&#xff08;即机器学习中的学习&#xff09;。 • 泛化&#xff08;generalization&#xff09;是指训练好的模型在 前所未…

2023JAVA 架构师面试 130 题含答案:JVM+spring+ 分布式 + 并发编程》...

此文包含 Java 面试的各个方面&#xff0c;史上最全&#xff0c;苦心整理最全 Java 面试题目整理包括基JVM算法数据库优化算法数据结构分布式并发编程缓存等&#xff0c;使用层面广&#xff0c;知识量大&#xff0c;涉及你的知识盲点。要想在面试者中出类拔萃就要比人付出更多的…

nginx怎么做负载均衡

Nginx怎么做负载均衡 Nginx 是一个高性能的开源反向代理服务器&#xff0c;可以用于实现负载均衡。负载均衡指的是将用户请求平均分配给多个服务器&#xff0c;以提高整体系统性能和可靠性。下面是一个详细介绍如何使用 Nginx 实现负载均衡的步骤&#xff1a; 步骤 1&#xf…

【Nodejs】Node.js简介

1.前言 Node 的重要性已经不言而喻&#xff0c;很多互联网公司都已经有大量的高性能系统运行在 Node 之上。Node 凭借其单线程、异步等举措实现了极高的性能基准。此外&#xff0c;目前最为流行的 Web 开发模式是前后端分离的形式&#xff0c;即前端开发者与后端开发者在自己喜…

提升Web3安全性和用户体验:元事务和加密技术的应用

在Web3中&#xff0c;去中心化应用程序&#xff08;DApps&#xff09;是一种基于区块链技术的应用程序&#xff0c;它们通过智能合约实现透明、安全、去中心化的业务逻辑。然而&#xff0c;DApps的使用门槛比传统的中心化应用程序更高&#xff0c;需要用户具备一定的技术知识&a…

工厂能耗管理系统解决方案

1、概述 随着碳达峰、碳中和成为政府工作主要任务&#xff0c;工厂作为能耗密集&#xff0c;用能情况较为复杂的大型建筑&#xff0c;有效的降低能源消耗&#xff0c;减少能源成本&#xff0c;避免用能过程中的“跑冒滴漏”现象&#xff0c;实施能效综合考评是个非常必要的管理…

C语言学习笔记 VScode设置C环境-06

目录 一、下载vscode软件 二、安装minGW软件 三、VS Code安装C/C插件 3.1 搜索并安装C/C插件 3.2 配置C/C环境 总结 一、下载vscode软件 在官网上下载最新的版本 Download Visual Studio Code - Mac, Linux, Windowshttps://code.visualstudio.com/download 二、安装minGW…

添加USB转串口设备驱动-迅为i.MX8M开发板

对于通过 USB 接口访问的模块&#xff0c;在 Linux 内核中集成 USB 驱动程序。我们需要配置内核选中支持 GSM 和 CDMA 模块的 USB 转串口驱动 > Device Drivers -> USB support (USB_SUPPORT [y]) -> USB Serial Converter support (USB_SERIAL [y]) -> USB driver…

2023 年第二届钉钉杯大学生大数据挑战赛初赛 初赛 A:智能手机用户监测数据分析 问题二分类与回归问题Python代码分析

2023 年第二届钉钉杯大学生大数据挑战赛初赛 初赛 A&#xff1a;智能手机用户监测数据分析 问题二分类与回归问题Python代码分析 相关链接 【2023 年第二届钉钉杯大学生大数据挑战赛初赛】 初赛 A&#xff1a;智能手机用户监测数据分析 问题一Python代码分析 【2023 年第二届…

day42-servlet下拉查询/单例模式

0目录 1.Servlet实现下拉查询&#xff08;两表&#xff09; 2.单例模式 1.实战 1.1 创建工程&#xff0c;准备环境... 1.2 接口 1.3 重写方法 1.4 servlet 1.5 list.jsp list.jsp详解 2.单例模式 2.1 饿汉模式&#xff1a;在程序加载时直接创建对象&#…

基于SpringBoot+Vue的摄影跟拍预定管理系统设计与实现(源码+lw+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

fastadmin 项目gitee管理

gitee创建一个仓库使用sourcetree等工具拉取代码使用phpstorm远程同步代码到本地设置忽略代码文件 注意&#xff1a;如果是直接把远程代码同步到本地&#xff0c;默认是你在 .gitignore中设置是无效的&#xff0c;代码一样会提交&#xff0c;需要先使用上面的截图去掉缓存&…

jmeter随记3:常用jmeter功能(附带场景)

常用jmeter功能&#xff08;附带场景&#xff09; 一、jmeter其他特性1、请求的接口有多个 且 域名相同2、 jmeter支持统一管理参数的设置a、创建HTTP Header Managerb、用户定义参数c、csv数据文件设置 3、接口a的返回值作为 接口b的入参a、 json提取器b、 正则表达式 4、if c…

小程序中vant-weapp时间选择使用方法

一、选择单个时间点&#xff1a; wxml&#xff1a; <van-celltitle"选择预约时间"value"{{ time }}"bind:click"onDisplay"/><van-calendarshow"{{ show }}"bind:close"onClose"bind:confirm"onConfirm"…

嵌入式Linux驱动开发——常见框架梳理

前言 本文主要介绍了Linux驱动开发中一些常用的驱动框架&#xff0c;platform、input、iic、spi等&#xff0c;硬件平台使用的是正点原子的imx6ull开发板。 一&#xff1a;Pinctrl子系统、Gpio子系统 不管什么框架最后都是要追溯到配置IO的电气属性和复用功能 如果要使用外部…