kotlin协程的理解

伴生对象:companion object 其实质等同于Java中的单例模式

协程:通常实现是用户态的任务协作式调度

  1. 一段可执行代码
  2. 可挂起/可恢复执行
  3. 概念上与语言无关,协程这个概念于1958年提出

依赖框架:

协程的启动:

1.协程体:协程中要执行的操作,是一个被suspend修饰的lambda表达式

传递末尾的lambda表达式,在Kotlin中有一个约定:

如果函数的最后一个参数是函数,那么作为相应的参数的传入的lambda表达式可以放在圆括号之外

2.协程体类:编译器会将协程体编译成封装协程体操作的匿名内部类

3.协程构建器:用于构建协程的函数:比如launch,async

4.挂起函数:由suspend修饰的函数,挂起函数只能在挂起函数或者协程体中调用,

5.挂起点:一般对应挂起函数被调用的位置

6.续体:Continuation

CoroutineScope:

  1. 是一个接口
  2. 只有一个属性:CoroutineContext(协程上下文),
  3. 是一个作用范围,可以通过CoroutineScope的扩展函数去创建协程(launch async),当这个作用范围被取消的时候,其内部协程也会被取消;GlobalScope除外
  • launch函数返回一个Job,可以通过Job进行管理协程
  • 为协程提供一个上下文CoroutineContext

GlobalScope:

  • 实现CoroutineScope接口,并且重写了上下文,返回一个EmptyCoroutineContext
  • 由object修饰,是一个单例对象,所以生命周期跟随整个应用,无法通过自身取消内部协程

launch函数的三个参数,也就是启动协程的三要素:

  • CoroutineContext 协程的上下文
  • CoroutineStart 协程的启动模式
  • suspend CoroutineScope.() -> Unit 协程体

CoroutineContext 协程上下文 ,这是一个数据集合接口声明,所包含的元素有:

  • 协程中Job
  • 调度器:CoroutineDispatcher
  • 协程名:CoroutineName
  • ...

CoroutineContext 的数据结构:链表

CombinedContext是CoroutineContext的一个实现类,也是链表中的具体实现节点,节点包含两个元素,

  • element:当前的节点集合元素,
  • left :CoroutineContext类型,指向链表的下一个元素

第四行:函数get,一个由operator修饰的操作符重载,对应"[ ]"操作符,通过key获取Element对象

第七行:函数fold,遍历当前集合的每一个Element,并对每一个元素进行opreator操作,将操作后的结果进行累加,以initial为其实开始累加,最终返回一个新的CoroutineContext 上下文

第十六行:函数plus,由operator修饰操作符重载,对应"+"操作符,合并两个CoroutineContext对象中的元素(这个元素可以是实现CoroutineContext 接口的任何对象:Job、CoroutineDispatcher、CoroutineName等等),将合并后的上下文返回,

从函数Plus中,我们可以清晰的看出,CoroutineContext的数据存储方式是一个链表,链表的每个节点是CombinedContext,并且存在拦截器的情况下,拦截器永远是链表的头结点 ,拦截器使用效率很高,这样可以保证更快的读取到拦截器

每个元素在创建的时候都会生成唯一的Key对象(单例模式),所以元素在添加到集合中时(plus)同类元素都会被最后的一个所覆盖

如果存在想相同的key的Element对象,则对其进程"覆盖"(先从集合中移除要plus的Element对象,返回一个移除后的集合,确保当前集合不包含要添加的元素)

以CombinedContext中的minusKey进行理解:

1.当我们在plus一个CoroutineContext元素时,需要对当前的CoroutineContext集合进行移除操作,

2.由于Key的唯一性,链表中不会存在重复的元素结点!首先从头结点的element中根据要添加元素的key进行查询,如果查询结果不为空,则直接返回left(意味着在这个链表存在要添加的元素,并且是当前结点的element,故而可以直接返回left)

3.如果2中的查询结果为空,则继续调用minusKey(递归)直到满足以下条件,退出递归

  • 移除结点后与移除前的left一样,那么也就意味着链表中不存在要添加的element,所以直接 返回这个链表
  • 移除结点后,链表为空,意味着当前链表只有一个结点,并且该结点中的element与要添加的一样,那么直接返回当前的节点的element
  • 当前链表就是一个空链表,那么将第三行代码中的newleft和elememt重新组合

Element:

1.第40行代码:每一个元素的类型是Element,而它又实现了CoroutineContext接口,所以Element即可以是一个集合中的元素,也可以是一个集合

CoroutineStart 是协程的启动模式,存在以下4种模式:

  • DEFAULT 立即调度,可以在执行前被取消
  • LAZY 需要时才启动,需要start、join等函数触发才可进行调度
  • ATOMIC 立即执行,执行前不可以被取消
  • UNDISPATCHED 立即在当前线程执行,直到遇到第一个挂起点(可能切线程)

协程体:suspend CoroutineScope.() -> Unit

一个lambda表达式,也就是协程中要执行的代码块,即launch函数的代码块;

为什么使用CoroutineScope扩展函数?

上面讲到,在CoroutineScope中只有一个属性,那就是协程上下文;这样我们可以在协程体中访问协程上下文这个对象

-----------------------------------协程中线程的挂起 和 切换----------------------------------------

Dispatchers:调度器,是协程中提供的线程调度器,用来切换线程,指定协程所运行的线程

源码分析:

DisPatchers中提供了4种类型的调度器:

  • Defaul:默认调度器,适合CPU密集型任务调度器,比如逻辑计算;
  • Main:UI调度器;
  • Unconfind:无限制(无拘束)调度器,对协程执行的线程不做限制,协程恢复时可以在任意线程;
  • IO:IO调度器,适合IO密集型任务调度器,比如读写文件,网络请求;

从源码中可以看到,这4种类型的调度器的类型均是:CoroutineDispatchers

CoroutineDispatchers:

继承自AbstractCoroutineContextElement,而AbstractCoroutineContextElement是Element的一个抽象实现类,所以调度器本身也是一个CoroutineContext,也可以存放在CoroutineContext集合中;同时实现了ContinuationInterceptor,一个拦截器接口

1.在上图代码中可以看到:ContinuationInterceptor实现了CoroutineContext.Element接口,所以拦截器也可以作为CoroutineContext集合的一个元素

2.在ContinuationInterceptor中定义了一个伴生对象Key,它的类型是CoroutineContext.Key,作为CoroutineContext集合元素的索引的理由:

  • 伴生对象的唯一性
  • 通过类型访问集合元素,更直观

3.interceptContinuation:对协程体类对象continuation的一次包装,并返回一个新的Continuation,

CoroutineDispatcher:继承自AbstractCroutineContextElement,同时实现了拦截器接口;

  • 说明了调度器的本质也是一个拦截器,在kotlin中所有的调度器都是继承自它来实现的自身调度逻辑
  • 调度器同时也可以作为CroutineContext集合中的元素

1.isDispatchNeeded:是否需要线程调度;

2.dispatch:线程调度,让一个runnable对象在指定的线程运行;

3.interceptContinuation:将协程体类对象包装成一个DispatchedContinuation对象;

DispatchedContinuation:使用线程调度器将协程体调度到指定的线程执行

1.实现了续体:Continuation,重写了resumeWith的内部实现逻辑,并且持有线程调度器;

2.有两个属性:

  • dispatcher:线程调度器
  • continuation:线程体类对象,也就是在包装成DispatchedContinuation时传入的协程体类对象

3.关注:delegate,实质就是DispatchedContinuation对象本身

4.resumeWith:首先通过isDispatchNeeded判断是否需要线程调度;

  • 如果需要线程调度,则使用dispatcher#dispatch进行调度,所需要的参数分别是:协程上下文和一个runnable对象(这里传入的this,即表示DispatchedContinuation对象本身,由于其继承自DispatchedTask,继续跟进会发现最终实现了Runnable接口),所以这个runnable会运行在调度的线程上
  • 如果不需要调度,则使用resumeWith,

5.runnable:从下面源码中可以看到,在run方法中首先从delegate中取出协程体对象,然后调用协程体的扩展函数resume,实质还是执行resumeWith

Dispatchers.Default默认调度器

dispatcher#dispatch()的实现是在调度器的具体实现类中,我们以Dispatchers.Default进行分析

1.useCoroutinesScheduler:默认情况是ture,所以会构建一个DefaultScheduler

2.IO调度器是Dispatchers.Default内的一个变量,并且它和Default调度器共享CoroutineScheduler线程池。

3.调度器的核心是重写dispatch()进行线程的切换,追溯到父类的dispatch:

ExperimentalCoroutineDispatcher

1.在ExperimentalCoroutineDispatcher中的dispatch的实现是通过调用coroutineScheduler.dispatch(),

2.CoroutineScheduler是一个Kotlin实现的线程池,提供协程运行的线程。

-----------------------------------协程中Worker线程----------------------------------------

Worker存在5种状态:

  • CPU_ACQUIRED 获取到cpu权限
  • BLOCKING 正在执行IO阻塞任务
  • PARKING 已处理完所有任务,线程挂起
  • DORMANT 初始态
  • TERMINATED 终止态

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

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

相关文章

大模型LLMs概述:利用大模型 (LLMs) 解决信息抽取任务

论文标题:Large Language Models for Generative Information Extraction: A Survey 论文链接:https://arxiv.org/pdf/2312.17617.pdf 论文主要探讨了大型语言模型(LLMs)在生成式信息抽取(IE)任务中的应用…

属性描述符初探——Vue实现数据劫持的基础

目录 属性描述符——Vue实现数据劫持的基础 一、属性描述符是什么? ​编辑 1.1、属性描述符示例 1.2、用属性描述符定义属性及获取对象的属性描述符 1.3、带有读取器和设置器的属性描述符 二、使用属性描述符的情景 2.1、封装和数据隐藏 使用getter和setter…

Desktop docker 部署 WordPress

Desktop Docker 部署 WordPress 之前都是在Linux里面玩的,今天看到别人在windwos下安装docker,一时兴起装了一个试试,效果一般,很吃硬盘空间和内存。 首先在docker官方下载桌面版,安装下一步一直到完成。 安装完docker会自动加入到环境变量,而且docker-compose也会一并安…

sql业务场景分析思路参考

1、时间可以进行排序,也可以用聚合函数对时间求最大值max(时间) 例如下面的例子:取最晚入职的人,那就是将入职时间倒序排序,然后limit 1 表: 场景:查找最晚入职员工的所有信息 se…

第十四届蓝桥杯省赛C++B组F题【岛屿个数】题解(AC)

题目大意 给定一个 01 地图,分别表示陆地和海,问地图中一共有多少块岛屿?另外,若一个岛屿在另一个岛屿的内部,则不统计。如下图中的大岛屿包含着内部的小岛屿,故内部小岛屿不计算,最终输出 1。…

vue3自定义全局指令和局部指令

1.全局指令 el:指令绑定到的DOM元素,可以用于直接操作当前元素,默认传入钩子的就是el参数,例如我们开始实现的focus指令,就是直接操作的元素DOM binding:这是一个对象,包含以下属性:…

【C#】ProgressBar进度条异步编程思想

1.控件介绍 进度条通常用于显示代码的执行进程进度,在一些复杂功能交互体验时告知用户进程还在继续。 在属性栏中,有三个值常用: Value表示当前值,Minimum表示进度条范围下限,Maximum表示进度条范围上限。 2.简单实…

简单的git pull fail Can‘t update has no tracked branch解决记录

简单的git pull fail Can‘t update has no tracked branch解决记录 1. 问题描述 上午同事使用idea拉取代码的时候,发现拉取不了,提示用户权限问题,之后修改了git用户信息,发现还是拉取不了分支代码,然后删除了git r…

对FPGA开发流程系统的学习

FPGA 开发流程: HDL(Hardware Design Language)和原理图是两种最常用的数字硬件电路描述方法,HDL 设计法具有更好的可移植性、通用性和模块划分与重用性的特点,在目前的工程设计中被广泛使用。所以,我们在…

WPF在.NET9中的重大更新:Windows 11 主题

在2023年的2月20日,在WPF的讨论区,WPF团队对路线的优先级发起了一次讨论。 对三个事项发起了投票。 第一个是Windows 11 主题 第二个是更新的控件 第三个是可空性注释 最终Windows 11 主题得票最高,WPF团队2023-2024的工作优先级就是Windows…

网安小贴士(8)IPv4与IPv6

一、前言 IPv4和IPv6都是互联网协议(IP)的版本,它们用于在互联网上标识和定位设备。 二、定义 IPv4(互联网协议第四版): IPv4是互联网协议的第一个广泛使用的版本,最初在1981年被标准化为RFC 7…

交换数字00

题目链接 交换数字 题目描述 注意点 numbers.length 2-2147483647 < numbers[i] < 2147483647 解答思路 不适用临时变量&#xff0c;可以先将numbers[0]和numbers[1]的信息都存到某个位置&#xff08;可以相加可以相减或其他位操作&#xff09;&#xff0c;然后另一…

SpringBoot 通过Knife4j集成API文档 在线调试

介绍 Knife4j 是一款基于 Swagger 构建的增强型 API 文档生成工具&#xff0c;它提供了更多的定制化功能和界面优化&#xff0c;使得生成的 API 文档更加美观和易用。它可以帮助开发者快速生成和管理 API 文档&#xff0c;支持在线调试和交互。 依赖 <!--knife4j--> &…

期末C语言易错知识点整理

1.在定义多维数组时&#xff0c;除了最左边的维度&#xff0c;其余的维度必须明确指定大小 2.int m[1][4]{4}; 定义的是一个 1 行 4 列的二维数组&#xff0c;初始化时提供了一个元素 4&#xff0c;其余元素默认初始化为 0&#xff0c;因此是正确的。 3.二维数组 a[3][6] 中的索…

谷粒商城学习笔记-05-项目微服务划分图

文章目录 一&#xff0c;商城业务服务-前端服务二&#xff0c;商城业务服务-后端服务三&#xff0c;存储服务四&#xff0c;第三方服务五&#xff0c;服务治理六&#xff0c;日志七&#xff0c;监控预警系统1&#xff0c;Prometheus2&#xff0c;Grafana3&#xff0c;Prometheu…

科技助力农业——土壤化肥测试仪

在农业生产中&#xff0c;土壤养分是作物健康生长的关键因素。然而&#xff0c;如何科学、精准地评估土壤养分含量&#xff0c;指导农民合理施肥&#xff0c;一直是农业科研和技术人员努力的方向。近年来&#xff0c;随着科技的进步&#xff0c;土壤化肥测试仪作为一种新型农业…

clion远程开发

clion远程开发 简要概括&#xff1a; 建立 SFTP 通讯&#xff0c;创建远程目录与本地目录的映射文件夹&#xff0c;就可以把本机文件夹中的文件用鼠标右键选中上全传&#xff0c;打开自动同步功能&#xff0c;后面更改文件就可以自动同步文件了。 一.新建SFTP远程链接服务 …

Unity游戏帧率查看软件Fraps

Download Fraps 3.5.99 free version 下载、安装、运行这个软件&#xff0c;左上角就会自动显示帧率

Java面试八股之MYISAM和INNODB有哪些不同

MYISAM和INNODB有哪些不同 MyISAM和InnoDB是MySQL数据库中两种不同的存储引擎&#xff0c;它们在设计哲学、功能特性和性能表现上存在显著差异。以下是一些关键的不同点&#xff1a; 事务支持&#xff1a; MyISAM 不支持事务&#xff0c;没有回滚或崩溃恢复的能力。 InnoDB…

通义千问 Qwen2,登顶国内第一大模型!

大家好&#xff0c;我是煎鱼。 7 月 9 日起&#xff0c;OpenAI 将正式终止对部分地区&#xff08;包含中国&#xff09;提供 API 服务&#xff0c;引起业内一片哗然&#xff0c;纷纷开始自检&#xff0c;找新的国内可用的国产化替代方案。 此时我有一个朋友的 Boss&#xff0c;…