当前位置: 首页 > news >正文

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
  • 为什么无栈协程不能被非协程函数嵌套调用? | 知乎
  • 浅谈有栈协程与无栈协程 | 知乎
  • 理解有栈无栈协程

相关文章:

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

协程 根据 是否保存切换 调用栈 &#xff0c;分为&#xff1a; 有栈协程&#xff08;stackful coroutine&#xff09;无栈协程&#xff08;stackless coroutine&#xff09; 在代码上的区别是&#xff1a;是否可在普通函数里调用&#xff0c;并暂停其执行。 Kotlin协程&…...

js实现九九乘法表

效果图 代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><script type"text/javascript">// 输出乘法口诀表// document.write () 空格 " " 换行…...

HarmonyOS鸿蒙应用开发(三、轻量级配置存储dataPreferences)

在应用开发中存储一些配置是很常见的需求。在android中有SharedPreferences&#xff0c;一个轻量级的存储类&#xff0c;用来保存应用的一些常用配置。在HarmonyOS鸿蒙应用开发中&#xff0c;实现类似功能的也叫首选项&#xff0c;dataPreferences。 相关概念 ohos.data.prefe…...

基于 IDEA 进行 Maven 工程构建

1. 构建概念和构建过程 项目构建是指将源代码、依赖库和资源文件等转换成可执行或可部署的应用程序的过程&#xff0c;在这个过程中包括编译源代码、链接依赖库、打包和部署等多个步骤。 项目构建是软件开发过程中至关重要的一部分&#xff0c;它能够大大提高软件开发效率&am…...

牛客周赛 Round 17 解题报告 | 珂学家 | 枚举贪心 + 二分最短路

前言 整体评价 其实T3最有意思&#xff0c; T4很典&#xff0c;是一道二分最短路径经典套路。 T3 如果尝试 增量差值最小 的最大梯度去贪心的话&#xff0c;会失败&#xff0c;需要切换思路。 珂朵莉 牛客周赛专栏 珂朵莉 牛客小白月赛专栏 A. 游游的正方形披萨 如果横竖差…...

喝口水都长胖?原来是“胖菌”惹的祸?!

减肥是一个永恒的话题&#xff0c;而关于长胖的原因&#xff0c;已有研究很多都聚焦在肥胖人群中肠道菌群的种类和丰度&#xff0c;很少有研究关注肠道微生物的基因与宿主肥胖的关系。近期发表在《Nature Medicine》的这项研究&#xff0c;使用来GWAS研究人类肠道微生物组与宿主…...

【C++干货基地】namespace超越C语言的独特魅力(文末送书)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…...

做一个简单的倒计时

<div>距离过年还有:<span></span></div><script>let div document.querySelector("div");let span document.querySelector("span");// 获取未来时间戳let future new Date("2024-2-10 00:00:00");// 获取当下…...

微服务环境搭建:docker+nacos单机

nacos需要连接mysql&#xff0c;持久化相关配置。 1. 部署好mysql后&#xff0c;新建nacos数据库然后初始化nacos脚本 -- -------------------------------------------------------- -- 主机: 192.168.150.101 -- 服务器版本: …...

Opencv轮廓检测运用与理解

目录 引入 基本理解 加深理解 ①比如我们可以获取我们的第一个轮廓,只展示第一个轮廓 ②我们还可以用一个矩形把我们的轮廓给框出来 ③计算轮廓的周长和面积 引入 顾名思义,就是把我们图片的轮廓全部都描边出来 也就是我们在日常生活中面部识别的时候会有一个框,那玩意就…...

Java 8的新特性简单分享(后续有系列篇~敬请期待)

Java 8的新特性分享 Java 8是Java语言迎来的一次革命性的更新&#xff0c;引入了众多强大的新特性&#xff0c;使得Java开发变得更加现代化和便捷。在这篇博客中&#xff0c;我们将深入探讨Java 8的一些主要特性&#xff0c;并通过丰富的案例演示展示它们的用法。 1. Lambda表…...

计算机网络-计算机网络的概念 功能 发展阶段 组成 分类

文章目录 计算机网络的概念 功能 发展阶段总览计算机网络的概念计算机网络的功能计算机网络的发展计算机网络的发展-第一阶段计算机网络的发展-第二阶段-第三阶段计算机网络的发展-第三阶段-多层次ISP结构 小结 计算机网络的组成与分类计算机网络的组成计算机网络的分类小结 计…...

246.【2023年华为OD机试真题(C卷)】分月饼(动态规划-JavaPythonC++JS实现)

🚀点击这里可直接跳转到本专栏,可查阅顶置最新的华为OD机试宝典~ 本专栏所有题目均包含优质解题思路,高质量解题代码(Java&Python&C++&JS分别实现),详细代码讲解,助你深入学习,深度掌握! 文章目录 一. 题目-分月饼二.解题思路三.题解代码Python题解代码J…...

java大数据hadoop2.9.2 Linux安装mariadb和hive

一、安装mariadb 版本centos7 1、检查Linux服务器是否已安装mariadb yum list installed mariadb* 2、如果安装了&#xff0c;想要卸载 yum remove mariadb rm -rf /etc/my.cnf rm -rf /var/lib/mysql 才能完全删除 3、安装mariadb 在线网络安装 yum install -y mari…...

Docker部署微服务问题及解决

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Docker容器命令案例&#xff1a;Nginx容器修改&#xff0c;Redis容器持久化 &#x1f4da;订阅专栏&#xff1a;Docker 希望文章…...

Android: alarm定时很短时,比如500ms,测试执行mPowerManager.forceSuspend()后,系统不会suspend

参考文档&#xff1a; https://blog.csdn.net/weixin_35691921/article/details/124961404 Android: alarm定时很短时&#xff0c;比如500ms&#xff0c;然后执行mPowerManager.forceSuspend()后&#xff0c;系统不会suspend&#xff0c;原因分析&#xff1a; static int ala…...

一个简单好用的C语言单元测试框架-Unity

Unity简介&#xff1a; Unity是一个用于C语言的轻量级单元测试框架。它由Throw The Switch团队开发&#xff0c;旨在简化嵌入式系统的单元测试。单元测试中单元的含义&#xff0c;单元就是人为规定的最小的被测功能模块&#xff0c;如C语言中单元指一个函数&#xff0c;Java里…...

ubuntu系统 vscode 配置c/c++调试环境

文章目录 1.安装插件2.目录结构3.cmake tools配置 1.安装插件 c/c插件 cmake cmake tools插件 2.目录结构 . ├── build ├── CMakeLists.txt ├── demo │ └── main.cpp ├── image.png ├── src │ ├── add.cpp │ └── add.hpp └── vsdebug.…...

算法练习-A+B/财务管理/实现四舍五入/牛牛的菱形字符(题目链接+题解打卡)

难度参考 难度&#xff1a;简单 分类&#xff1a;熟悉OJ与IDE的操作 难度与分类由我所参与的培训课程提供&#xff0c;但需要注意的是&#xff0c;难度与分类仅供参考。以下内容均为个人笔记&#xff0c;旨在督促自己认真学习。 题目 A B1. A B - AcWing题库财务管理1004:财…...

XSS语句

XSS测试语句 在测试网站是否存在XSS漏洞时&#xff0c;应该输入一些标签如<,>输入后查看网页源代码是否过滤标签&#xff0c;如果没过滤&#xff0c;很大可能存在XSS漏洞。 <h5>1</h5> <span>1</span> <SCRIPT>alert(document.cookie)&l…...

AD导出BOM表 导出PDF

1.Simple BOM: 这种模式下&#xff0c;最好在pcb界面&#xff0c;这样的导出的文件名字是工程名字&#xff0c;要是在原理图界面导出&#xff0c;会以原理图的名字命名表格。 直接在菜单栏 报告->Simple BOM 即可导出物料清单&#xff0c;默认导出 comment pattern qu…...

linux 的nobody是什么用户? 对安全有没有影响?

目 录 一、前言&#xff1a;nobody是不是可疑用户&#xff1f; 二、Linux系统中的nobody用户&#xff1f; 二、有nobody用户存在&#xff0c;安全吗&#xff1f; 一、前言&#xff1a;nobody是不是可疑用户&#xff1f; 在前面一篇文章“Linux安全问题,如何查看哪…...

2024年华数杯国际数学建模B 光伏电(Problem B: Photovoltaic Power)完整思路以及源代码分享

背景 中国的电力构成包括传统的能源发电&#xff08;如煤炭、石油和天然气&#xff09;、可再生能源发电 &#xff08;如水力发电、风能、太阳能和核能&#xff09;和其他形式的电力。这些发电方式在满足中 国巨大的电力需求方面发挥着至关重要的作用。根据最新数据&#xf…...

在 Spring MVC 中,用于接收前端传递的参数的注解有以下几种

目录 RequestParam&#xff1a; PathVariable&#xff1a; RequestBody&#xff1a; RequestHeader&#xff1a; CookieValue&#xff1a; RequestParam&#xff1a; 用于获取请求参数的值。可以指定参数名称和默认值。示例代码&#xff1a; GetMapping("/users&q…...

K8s常用命令

查看集群各节点的状态 部署应用 删除一个service服务 查询service服务列表 kubectl get services 查看网络资源 kubectl get svc pod 创建一个namespace kubectl create namaspace namespace名称 创建一个pod 通常不需要创建pod 查看pod kubectl get pods kube…...

MySQL的基本操作

目录 序言 一、SQL语句&#xff08;Structured Query Language&#xff09; 1.1 SQL简介 1.2 SQL语句的分类 1.3 SQL语句的书写规范 二、数据库操作 2.1 查看库 2.2 创建库 2.3 切换库 2.4 删除库 三、MySQL字符集 3.1 MySQL字符集的分类 3.2 UTF8和UTF8MB4的区别…...

【b站咸虾米】chapter4_vue组件_新课uniapp零基础入门到项目打包(微信小程序/H5/vue/安卓apk)全掌握

课程地址&#xff1a;【新课uniapp零基础入门到项目打包&#xff08;微信小程序/H5/vue/安卓apk&#xff09;全掌握】 https://www.bilibili.com/video/BV1mT411K7nW/?p12&share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 四、vue组件 uni-app官网 …...

Java网络编程——UDP通信原理

一、TCP和UDP概述 传输层通常以TCP和UDP协议来控制端点与端点的通信 TCPUDP协议名称传输控制协议用户数据包协议是否连接面向连接的协议。数据必须要建立连接无连接的协议&#xff0c;每个数据报中都给出完整的地址信息&#xff0c;因此不需要事先建立发送方和接受方的连接是…...

Spring | Srping AOP (AOP简介、动态代理、基于“代理类”的AOP实现)

目录: 1.Spring AOP简介1.1 AOP简介1.2 AOP术语 2.动态代理2.1 JDK动态代理2.2 CGLIB代理 3.基于“代理类”的AOP实现3.1 Spring的通知类型3.2 ProxyFactoryBean ( 可通知.xml配置文件完成aop功能 ) 1.Spring AOP简介 1.1 AOP简介 Spring的AOP模块&#xff0c;是Spring框架体系…...

StarRocks 生成列:百倍提速半结构化数据分析

半结构化分析主要是指对 MAP&#xff0c;STRUCT&#xff0c;JSON&#xff0c;ARRAY 等复杂数据类型的查询分析。这些数据类型表达能力强&#xff0c;因此被广泛应用到 OLAP 分析的各种场景中&#xff0c;但由于其实现的复杂性&#xff0c;对这些复杂类型分析将会比一般简单类型…...