Kotlin 协程使用及其详解
Kotlin协程,好用,但是上限挺高的,我一直感觉自己就处于会用,知其然不知其所以然的地步。
做点小总结,比较浅显。后面自己再继续补充吧。
一、什么是协程?
Kotlin 协程是一种轻量级的并发编程方式,用于简化异步代码的编写。它允许你编写看似同步的代码来处理异步任务,使代码更加简洁、可读且易于维护。协程广泛应用于 Android 开发中,用于网络请求、数据库操作等需要异步执行的任务。
- 协程是一种语法糖 协程的出现是来解决异步问题的,但它本身却不提供异步的能力,协程某种意义上更像是一种语法糖,它为我们隐藏了异步调用和回调的细节,让我们更关注于业务逻辑的实现。
- 一句话概括,协程是一种轻量级的方便操作异步代码的语法糖,而它本身不提供异步能力。
二、Kotlin 协程的核心概念
-
协程 (Coroutine):一种轻量级的线程。协程可以在不阻塞主线程的情况下挂起和恢复,使得代码能够异步执行而不增加线程开销。协程在 Kotlin 中由
suspend函数来支持,避免回调地狱的情况。 -
挂起函数 (
suspendfunction):使用suspend关键字修饰的函数,可以在协程中挂起。挂起函数不会阻塞线程,而是挂起当前协程,直到任务完成后再继续执行。例如:
suspend fun fetchData(): String {// 模拟网络请求delay(1000) // 挂起 1 秒,不会阻塞线程return "Data fetched"
}
-
挂起 (Suspend) 和恢复 (Resume):当协程执行到
delay、withContext等挂起函数时,它会暂停执行并释放资源,一旦挂起函数完成任务,协程会恢复执行。这种机制使得协程能够在同一线程上无缝切换,从而提高性能。 -
作用域 (
CoroutineScope):协程作用域定义了协程的生命周期。常见的协程作用域有GlobalScope、CoroutineScope、viewModelScope和lifecycleScope,它们决定了协程的启动与取消。作用域有助于自动管理协程,确保在不再需要协程时取消它,避免资源泄漏。 -
上下文 (
CoroutineContext):协程的上下文包含了协程的调度器(比如Dispatchers.Main、Dispatchers.IO)和其他信息。上下文指定了协程在哪个线程或线程池上执行,调度器为协程提供执行环境。
三、协程的特点
轻量
- 一个线程中可以包含多个协程,协程支持挂起,不会让正在运行协程的线程阻塞,与阻塞线程相比,挂起协程的操作更轻量
- 内存泄漏更少
- 协程使用了结构化并发机制,可以在一个作用域内执行多个操作,可以一次性全部取消掉,这样就不用像 RxJava 一样要自己把 Disposable 放在 CompositeDisposable 里
- 内置取消支持
- 当我们取消一个协程时,取消操作会在运行中的整个协程层次结构内传播,也就是父协程取消后,子协程也会被取消
- Jetpack支持
- 集成 Jetpack 中的 ViewModel 、Lifecycle 和 LiveData 都提供了对应的协程作用域
- Kotlin 协程框架中的挂起函数有另外一个好处,就是可以在编译时就让方法的调用方知道这是一个耗时的操作,需要确定这个操作要放在哪个线程执行,这样就不用像 Android 框架对主线程网络请求的禁止方式一样,在运行时才抛出异常。
四、协程和线程的区别
(1)协程是编译器级别的,线程是系统级别的。协程的切换是由程序来控制的,线程的切换是由操作系统来控制的。
(2)协程是协作式的,线程是抢占式的。协程是由程序来控制什么时候进行切换的,而线程是有操作系统来决定线程之间的切换的。
(3)一个线程可以包含多个协程。
(4)Java中,多线程可以充分利用多核cpu,协程是在一个线程中执行。
(5)协程适合io密集型的程序,多线程适合计算密集型的程序(适用于多核cpu的情况)。当你的程序大部分是文件读写操作或者网络请求操作的时候,这时你应该首选协程而不是多线程,首先这些操作大部分不是利用cpu进行计算而是等待数据的读写,其次因为协程执行效率较高,子程序切换不是线程切换,是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
(6)使用协程可以顺序调用异步代码,避免回调地狱。
五、协程的使用
Kotlin 提供了丰富的协程构建器,如 launch 和 async,分别用于启动协程并发任务。
1. launch
launch 是一种最常用的协程构建器,用于启动一个新协程,并且不会阻塞主线程。它的返回值是 Job,可以用于取消协程。
GlobalScope.launch {val result = fetchData()println(result)
}
2. async
async 用于并发执行多个任务,适合需要返回结果的情况。它的返回值是 Deferred,可以通过 await() 来获取执行结果。
CoroutineScope(Dispatchers.Main).launch {val result1 = async { fetchData() }val result2 = async { fetchData() }println(result1.await() + result2.await())
}
六、Job的使用
我们在使用launch的时候,就启动了一个协程,launch方法会返回一个job。
1.使用job.cancel()取消一个协程
fun main() {val job = GlobalScope.launch {delay(1000L)println("World!")}job.cancel()println("Hello,")}
因为协程被取消了,所以只会打印Hello。
2、join()等待协程执行完毕
作用类似于Thread.join()函数,join()后面的代码会等到协程结束再执行,结果如下:
fun main() = runBlocking {val job = GlobalScope.launch {delay(1000L)println("World!")delay(1000L)}println("Hello,")job.join() println("Good!")
}//依次打印
Hello,
World!
Good!
七、 其他注意事项
在Activity或Fragment中使用协程时,要尽量避免使用GlobalScope,因为GlobalScope是生命周期是process级别的,所以上面的例子中,即使Activity或Fragment已经被销毁,协程仍然在执行。
建议使用具有生命周期协程LifecycleScope。
关于kotlin相关的同步,异步,回调,阻塞,这篇文章很生动:
https://juejin.cn/post/7373502637729513506
https://juejin.cn/post/7373502637729513506retrofit搭配协程
https://juejin.cn/post/6962921891501703175
https://juejin.cn/post/6962921891501703175emmm...感觉写的很浅,还有很多知识点没有概括到,后面补充
相关文章:
Kotlin 协程使用及其详解
Kotlin协程,好用,但是上限挺高的,我一直感觉自己就处于会用,知其然不知其所以然的地步。 做点小总结,比较浅显。后面自己再继续补充吧。 一、什么是协程? Kotlin 协程是一种轻量级的并发编程方式&#x…...
计算机组成原理--三章四章
这里写目录标题 第三章:存储系统3.1 存储系统基本概念引入存储器的层次结构简介产品 存储器的分类按层次分类按照介质分类按照存取方式分类按照信息的可更改性按照信息的可保护性 存储器的性能指标存储容量单位成本存储速度 总结 3.2主存储器的基本组成半导体元器件…...
单片机工程使用链接优化-flto找不到定义_链接静态库
IDE: CLion HOST: Windows 11 MinGW:x86_64-14.2.0-release-posix-seh-ucrt-rt_v12-rev0 GCC: arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi 示例工程:https://github.com/ichliebedich-DaCapo/STM…...
UniTask/Unity的PlayerLoopTiming触发顺序
开始尝试在项目中使用UniTask,发现其中的UniTask.Yield确实很好用,还可以传入PlayerLoopTiming来更细致的调整代码时机,不过平常在Mono中接触的只有Awake,Start,Update等常用Timing,其他的就没怎么接触了&a…...
【报错记录】Steam迁移(移动)游戏报:移动以下应用的内容失败:XXX: 磁盘写入错误
前言 由于黑神话悟空,导致我的2TB的SSD系统盘快满了,我又买了一块4TB的SSD用来存放游戏,我就打算把之前C盘里的游戏移动到D盘,结果Steam移动游戏居然报错了,报的还是“磁盘写入错误”,如下图所示ÿ…...
C 语言学习-04【结构化程序设计】
1、单分支结构语句 用单分支结构进行奇偶判断: #include <stdio.h>int main() {int num;printf("Please enter an integer: ");scanf("%d", &num);if (num % 2 ! 0) {printf("%d is odd! \n", num);}if (num % 2 0) {prin…...
机器视觉:轮廓匹配算法原理
轮廓匹配的模板变量主要包括模板图像(Template)和待检测图像(Source Image) 在轮廓匹配中,模板变量主要包括一下几个关键部分: 模板图像(Template):这是进行匹配的…...
动力商城-02 环境搭建
1.父工程必须满足:1.1删除src目录 1.2pom 2.依赖继承 //里面的依赖,后代无条件继承<dependencies></dependencies>//里面的依赖,后代想要继承,得自己声明需要使用,可以不写版本号,自动继承&l…...
【react】Redux基础用法
1. Redux基础用法 Redux 是一个用于 JavaScript 应用的状态管理库,它不依赖于任何 UI库,但常用于与 React 框架配合使用。它提供了一种集中式的状态管理方式,将应用的所有状态保存在一个单一的全局 Store(存储)中&…...
使用Python分析股票价格数据并计算移动平均线的实用指南
使用Python分析股票价格数据并计算移动平均线的实用指南 在金融市场中,移动平均线(Moving Average, MA)是一种常用的技术分析工具,用于平滑价格数据,帮助投资者识别趋势。本文将详细介绍如何使用Python分析股票价格数据,并计算移动平均线。我们将通过一个实际的案例来演…...
如何解决FPS低的问题?代码优化方法有哪些?
如果你是一名游戏开发者,或者对电脑性能有所追求的用户,那么你一定遇到过帧率(FPS)低的问题。帧率低会导致游戏卡顿、画面不流畅等问题,极大地影响了用户体验。本文将从代码层面探讨FPS低的原因,并提供一些…...
QT信号和槽与自定义的信号和槽
QT信号和槽与自定义的信号和槽 1.概述 这篇文章介绍下QT信号和槽的入门知识,通过一个案例介绍如何创建信号和槽,并调用他们。 2.信号和槽使用 下面通过点击按钮关闭窗口的案例介绍如何使用信号和槽。 创建按钮 在widget.cpp文件中创建按钮代码如下 …...
LC:二分查找——杂记
文章目录 268. 丢失的数字162. 寻找峰值 268. 丢失的数字 LC将此题归类为二分查找,并且为简单题,下面记一下自己对这道题目的思考。 题目链接:268.丢失的数字 第一次看到这个题目,虽然标注的为简单,但肯定不能直接排…...
GA/T1400视图库平台EasyCVR多品牌摄像机视频平台前端监控摄像头镜头的基础知识
在现代安全监控系统中,摄像机镜头作为捕捉图像的关键组件,其选择和应用直接影响到监控图像的质量和系统的整体性能。随着技术的发展,摄像机镜头的种类和功能也在不断扩展,以适应各种复杂的监控环境和需求。对于相机成像来讲&#…...
【C++】踏上C++的学习之旅(六):深入“类和对象“世界,掌握编程的黄金法则(一)
文章目录 前言1. "面向过程"和"面向对象"的碰撞1.1 面向过程1.2 面向对象 2. "类"的引入3. "类"的定义3.1 🍉语法展示:3.2 "类"的两种定义方式3.3 "类"的命名规则 4. 类的访问限定符以及封…...
【物联网技术】ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式
前言:讲解如何在ESP8266 WIFI模块在STA模式下作为TCP客户端与网络调试助手(TCP服务器)上电自动进入透传数据模式,而不需重新再发指令配置进入透传模式。 演示视频: ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式 wifi模块在STA模式下作为TCP客户端相…...
重构代码之用委托替代继承
在代码重构中,用委托替代继承 是一种用于改善代码设计和提高灵活性的重要技术。它的核心思想是,将子类与父类的直接继承关系转换为委托关系,即子类不再直接继承父类,而是通过持有父类的实例来访问所需的功能。 一、为什么需要用委…...
软件设计师下午题UML15分
一、涉及到的图及对应关系 二、例题 1.用例图和类图的例题 解析及答案 2.状态图和类图的例题 3.通信图和类图例题 例题...
css background-image背景图片轮播
1、CSS背景样式有以下几种: 背景颜色(background-color):设置元素的背景颜色。背景图片(background-image):设置元素的背景图片。背景重复(background-repeat)ÿ…...
java---认识异常(详解)
还有大家来到权权的博客~欢迎大家对我的博客提出意见哦,有错误会及时改进的~点击进入我的博客主页 目录 一、异常的概念及体系结构1.1 异常的概念1.2 异常的体系结构1.3异常的分类 二、异常的处理2.1防御式编程2.2 异常的抛出2.3 异常的捕获2.3.1异常声明throws2.3.…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...
阿里云Ubuntu 22.04 64位搭建Flask流程(亲测)
cd /home 进入home盘 安装虚拟环境: 1、安装virtualenv pip install virtualenv 2.创建新的虚拟环境: virtualenv myenv 3、激活虚拟环境(激活环境可以在当前环境下安装包) source myenv/bin/activate 此时,终端…...
在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7
在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...
