Kotlin协程的JVM实现源码分析(下)

协程 根据 是否保存切换 调用栈 ,分为:

  1. 有栈协程(stackful coroutine)
  2. 无栈协程(stackless coroutine)

在代码上的区别是:是否可在普通函数里调用,并暂停其执行。

Kotlin协程,必须在挂起函数中调用和恢复,属于 无栈协程

常见的语言,协程实现:

  • 有栈协程:Go、Lua
  • 无栈协程:Kotlin、C++ 20、Clojure、JavaScript

二、无栈协程 和 Continuation

2.1 CPS(Continuation-passing-style)

在上篇源码分析中,不难发现 执行的结果,都是通过 Continuation 来返回。

2.1.1 Continuation

Continuation 就是 一个通用的回调接口,返回 Result<T> 值 或 异常。

Continuation is a generic callback interface. —— Roman Elizarov

public interface Continuation<in T> {public val context: CoroutineContextpublic fun resumeWith(result: Result<T>)
}
2.1.2 CPS

挂起函数 调用 其他挂起函数时,会将自己的 Continuation对象 作为 completion 参数 传递,
这种传递Continuation的方式,称为 连续传递风格(Continuation-passing-style),简称为 CPS

挂起函数 编译后,会创建基于 ContinuationImpl 对象,把 调用者Continuation 传给 completion 构造参数:

internal abstract class BaseContinuationImpl(public val completion: Continuation<Any?>?
)
2.1.3 Continuation结果返回

上篇知道 协程执行在 BaseContinuationImpl.resumeWith 方法,
同样 结果返回逻辑 也在这里,看下代码:

和 传递逻辑顺序 相反,结果按 逐步向上 返回。

resumeWith

分析:当获取结果后,通过 while 循环,completion 将结果向上传递,一般是协程 StandaloneCoroutine 作为最终的 completion 完成结果回调。

2.2 状态机

无栈协程,是通过 状态机状态 保存恢复 来实现协程挂起恢复。

和 每个 回调 都要创建 回调对象 相比,状态机 通过 状态 记录 执行位置,

当 挂起函数完成后,只需 恢复状态 接着执行后面的代码。

其实就是通过 switch(label) 做判断,判断位置执行。

状态机 vs 回调,有以下几个优点:

  1. 复用 方法对象和状态,避免每次分配对象
  2. 简化 循环 和 使用 高阶函数

以下面 请求解析数据 为例,launch {} 对应的 lambda挂起函数 ,分析 Kotlin 状态机状态:

GlobalScope.launch {// 挂起点1val data = getData()// 挂起点2val result = parseData(data)println("data: $data, result: $result")
}

Kotlin编译后逻辑,以 伪代码 表示:

class $main$1 extends SuspendLambda {// 挂起点的位置int label;// 状态 对象 保存 和 恢复Object L$0;// 更多状态: L$1 L$2 ...Object invokeSuspend(Object result) {Object obj;switch (this.label) {case 0:this.label = 1;obj = getData(this);// 表示挂起,存储 状态 label = 1,// 恢复时再次调用 invokeSuspend,恢复执行下面if (obj == COROUTINE_SUSPENDED) {return COROUTINE_SUSPENDED;}// 没有break,如果没有挂起,直接 执行下面的过程case 1:// 挂起恢复后String data = (String) result;// 如果没有挂起,直接执行则是:// String data = (String) obj;this.label = 2;// 保存 状态this.L$0 = data;obj = parseData(data, this);if (obj == COROUTINE_SUSPENDED) {return COROUTINE_SUSPENDED;}case 2:// 挂起恢复后Integer num = (Integer) result;// 如果没有挂起,直接执行则是:// Integer num = (Integer) obj;// 恢复状态String data = (String) this.L$0;System.out.println("data: " + data + ",num: " + num);return Unit.INSTANCE;default:throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");}}
}

2.3 CPS Transform

上面说到调用挂起函数 continuation 会作为函数参数传递,但是 声明挂起函数时,
并没有 continuation参数。而是 Kotlin 会在参数列表 自动加上 Continuation 参数,这个操作叫做 CPS Transform

举例,下面挂起函数:

suspend fun <T> CompletableFuture<T>.await(): T

而在 CPS Transform 后,实际的代码是:

fun <T> CompletableFuture<T>.await(continuation: Continuation<T>): Any?

小结

  • Kotlin协程,通过 状态机 实现,复用闭包。
  • 挂起函数, 编译成 Continuation 回调对象,CPS。
  • suspend 以同步的编程方式,执行异步方法

文档

  • Coroutine | Wikipedia
  • KEEP | Kotlin
  • KotlinConf 2017 - Deep Dive into Coroutines on JVM
  • ContinuationImpl.kt
  • 为什么无栈协程不能被非协程函数嵌套调用? | 知乎
  • 浅谈有栈协程与无栈协程 | 知乎
  • 理解有栈无栈协程

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

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

相关文章

一、基础数据结构——2.队列——3.双端队列和单调队列1

参考资料&#xff1a;《算法竞赛》&#xff0c;罗勇军 郭卫斌 著 本博客作为阅读本书的学习笔记&#xff0c;仅供交流学习。 建议关注 罗勇军老师博客 删除线格式 今天想到考完研去找工作面试被问到的问题&#xff1a; C与C有什么区别&#xff1f; 我当时的答案&#xff08;毫无…

【git分支管理策略】

文章目录 前言一、分支管理策略简介二、git基本操作三、git分支远程分支本地分支 四、gitflow分支管理策略分支定义gitflow分支管理策略评价 五、GITHUB FLOW分支管理策略分支使用流程创建分支&#xff08;Create a branch&#xff09;新增提交(add and commit)提出 Pull 请求&…

C++泛型编程-类模板的项目实战实现基础的Vector的编写

请设计一个数组模板类&#xff08; Vector &#xff09;&#xff0c;完成对 int 、 char 、 float 、 double 以 及任意的自定义类等类型元素进行管理。 需求 a. 实现构造函数 b. 实现拷贝构造函数 c. 实现 cout << 操作 d. 实现下标访问符 [] 的重载操作 …

webench源码阅读

简介 webbench是一款用C编写的开源工具&#xff0c;主要用来在Linux下进行网站压力测试。最多可以模拟3万个连接去测试网站的负载能力&#xff0c;并可以设置运行的客户端数、测试时间、使用的http协议版本、请求方法、是否需要等待服务器响应等选项&#xff0c;最后统计每分钟…

CTF-PWN-堆-【chunk extend/overlapping-1】

文章目录 chunk extend/overlappingfastbin与topchunk相邻free时候不会合并unsortedbinchunk中与topchunk相邻的被free时会合并extend向后overlapping先修改header&#xff0c;再free&#xff0c;再malloc先free&#xff0c;再修改header&#xff0c;再malloc extend向前overla…

Filter简单了解

1、filter能干嘛 过滤器实际上就是对web资源进行拦截&#xff0c;做一些处理后交给下一个过滤器或者servlet处理&#xff0c;通常都是拦截request的&#xff0c;也可以对response进行拦截处理&#xff1b; 2、面试考点&#xff1a;filter能干嘛&#xff08;应用场景&#xff0…

STL标准库(二)序列容器之vector

vector 动态数组 本质是向量&#xff0c;一个无限续存的连续内存空间 int main() { std::vector<int> obj(5); 创建一个容量为5且默认值为0的vector std::vector<int> obj(5&#xff0c;12138); 创建一个容量为5且默认值为12138的vector std::cout << obj.…

多维时序 | Matlab实现CNN-GRU-Mutilhead-Attention卷积门控循环单元融合多头注意力机制多变量时间序列预测

多维时序 | Matlab实现CNN-GRU-Mutilhead-Attention卷积门控循环单元融合多头注意力机制多变量时间序列预测 目录 多维时序 | Matlab实现CNN-GRU-Mutilhead-Attention卷积门控循环单元融合多头注意力机制多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍…

深度学习-自然语言推断

自然语言推断&#xff08;natural language inference&#xff09;主要研究 假设&#xff08;hypothesis&#xff09;是否可以从前提&#xff08;premise&#xff09;中推断出来&#xff0c; 其中两者都是文本序列。 换言之&#xff0c;自然语言推断决定了一对文本序列之间的逻…

退出微软账号,edge/必应退出账号

微软账号退出&#xff1a;搜的教程都是说改成本地帐号&#xff0c;但是我的已经是本地帐号&#xff0c;操作没用。 但是找到了退出edge/必应浏览器账号的方法&#xff0c;见下图。 参考链接&#xff1a;奶酪真好次个人动态-奶酪真好次动态记录-哔哩哔哩视频 (bilibili.com)

【Linux】基本指令收尾

文章目录 日期查找打包压缩系统信息Linux和Windows互传文件 日期 这篇是基本指令的收尾了&#xff0c;还有几个基本指令我们需要说一下 首先是Date&#xff0c;它是用来显示时间和日期 直接输入date的话显示是有点不好看的&#xff0c;所以我们可以根据自己的喜欢加上分隔符&…

python常用命令汇总

一、下载对应源地址的库 以下是国内的python库原地址 清华&#xff1a;-i https://pypi.tuna.tsinghua.edu.cn/simple 阿里云&#xff1a;-i http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 -i https://pypi.mirrors.ustc.edu.cn/simple/ 华中理工大学&#xff1a;-…

使用 Vector 在 Kubernetes 中收集日志

多年来&#xff0c;我们一直在使用 Vector 在我们的 Kubernetes 平台中收集日志&#xff0c;并成功地将其应用于生产中以满足各种客户的需求&#xff0c;并且非常享受这种体验。因此&#xff0c;我想与更大的社区分享它&#xff0c;以便更多的 K8s 运营商可以看到潜力并考虑他们…

【 CSS 】基础1

“坚持就是胜利。” - 温斯顿丘吉尔 【 CSS 】基础 1 CSS 简介 CSS 是层叠样式表 ( Cascading Style Sheets ) 的简称.有时我们也会称之为 CSS 样式表或级联样式表。CSS 也是一种标记语言CSS 主要用于设置 HTML 页面中的文本内容&#xff08;字体、大小、对齐方式等&#xff…

力扣日记1.22-【回溯算法篇】216. 组合总和 III

力扣日记&#xff1a;【回溯算法篇】216. 组合总和 III 日期&#xff1a;2023.1.22 参考&#xff1a;代码随想录、力扣 216. 组合总和 III 题目描述 难度&#xff1a;中等 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数…

Python使用gRPC入门,定义proto文件和收发消息

gRPC 一开始由 google 开发&#xff0c;是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。 本文通过一个简单的 Hello World 例子来向您介绍 gRPC 。 Grpc官方文档地址&#xff1a;Quick start | Python | gRPC gRPC 是什么&#xff1f; gRPC 也是基于以下理念&#…

Python武器库开发-武器库篇之Quake360-API使用(四十七)

Python武器库开发-武器库篇之Quake360-API使用(四十七) Quake360是一款网络资产搜索引擎&#xff0c;旨在帮助用户快速定位和识别网络上的资产信息。它具有强大的搜索功能&#xff0c;可以搜索并展示各种类型的网络资产&#xff0c;包括域名、IP地址、子域名、端口信息等。同时…

Unity编程#region..#endregion以及面板提示语标签[Tooltip(““)]

C#中的#region..#endregion 在Unity中&#xff0c;#region和#endregion是用于代码折叠的预处理指令。它们并不是Unity特有的&#xff0c;而是C#语言本身提供的功能。 #region用于标记一段代码的开始&#xff0c;而#endregion用于标记一段代码的结束。在编辑器中&#xff0c;可…

流量劵可以用来做什么?如何使用电脑提高工作效率

好久没来看了,一分钱收益也没有,不过倒是起了一点知识的积累传播。正确与否先不去考究,从有文字记载的历史来看,有记录这本身就是一种进步。最近偶尔会用到电脑处理一些EXCEL文档,很多的工作都是重复和简单的数学计算,然后去核对数据是不是勾稽得当。工作虽然不多,但也是…

橡木桶陈酿:木材选择、烤制程度与陈酿时间

在威士忌的酿造过程中&#xff0c;橡木桶陈酿是一个至关重要的环节。橡木桶不仅为威士忌提供了特别的香气和风味&#xff0c;还赋予其丰富的颜色和味蕾。本文将深入探讨橡木桶陈酿的奥秘&#xff0c;特别是木材选择、烤制程度以及陈酿时间对威士忌风味的影响&#xff0c;以雷盛…