Kotlin协程源码简单聊一聊,浅浅看看表层

2023-10-26

outside_default.png

/   今日科技快讯   /

近日,经历了一次停办,两次规模严重缩水之后,2023年世界移动通信大会(MWC)终于再现往日盛况:有来自200多个国家和地区的2000多家厂商参加,并在此次展会上发布了最新的产品与科技,仅中国就有100余家厂商参展。

每年的MWC都被称作“全球移动通信技术发展的风向标”,今年大会以“时不我待——明日科技,将至已至”为主题,具体又围绕着5G新动能、数字万物、开放网络、超越现实+ 、金融科技等五大热点主题展开。

/   作者简介   /

本篇文章转自史大拿的博客,文章主要分享了对kotlin协程源码的分析,相信会对大家有所帮助!

原文地址:

https://juejin.cn/post/7204752219915288636

/   前言   /

kotlin协程源码十分庞大,本篇只能把我理解的源码聊一聊,不会特别深入研究,只会浅浅的看看表层。本来计划协程系列是10篇左右,后续是flow热流冷流之类的,冷流操作符之类的应该不会在写了,flow当作Rxjava来用就可以,后续可能还会写一篇关于热流的文章。也可能没有:) 主要是不好写,文字写出来还是比较生硬。

/   launch 浅析   /

源码阅读从最简单的一个launch开始!

outside_default.png

在launch的时候,会执行CoroutineScope.newCoroutineContext函数。这里会传入一个EmptyCoroutineContext。CoroutineScope.newCoroutineContext会走foldCopies , 这个函数是用来合并2个协程的。

先来看看 foldCopies的参数:

  • coroutineContext // 可以看出,此时coroutineContext为JobImpl我们稍后来看看它是在什么时候赋值的

  • context // 默认什么都没有传,是EmptyCoroutineContext

  • true // isNewCoroutine是否创建新的Coroutine

我们在创建CoroutineScope的时候,会对coroutineContext赋值。

outside_default.png

我们在创建协程作用域的时候,会初始化一个Job,Job的默认实现为JobImpl。好了,再回到CoroutineScope.newCoroutineContext方法。

afddacbdd5e09b0629ec6a75e3fe9f3f.png

执行完foldCopies后,我们知道此时返回结果combined = jobImpl,最后当返回的时候if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null)最终给他添加一个默认调度器Dispatchers.Default。

tips:ContinuationInterceptor是协程拦截器,下面会说,不要急。

再次回到主线流程。

e9ad6d3f1234252f9765f41cebd83b5d.png

此时newContext = [JobImpl,Dispatchers.Default],如果说有子协程的情况下,newCoroutineContext这个方法就会使用最新的coroutineContext。例如这样:

outside_default.png

这都是foldCopies的功劳,foldCopies的细节就不看了,没意义。比较烧脑,不想看。再接着往下走:

outside_default.png

在聊协程启动模式的时候说过,coroutineStart一共有4种模式:

  • DEFAULT

  • LAZY

  • UNDISPATCHED

  • ATOMIC // 实验中

此时会判断是否是懒加载模式,很明显不是懒加载,所以会走 StandaloneCoroutine。StandaloneCoroutine会通过 handleJobException 捕获一些异常。比如说在JVM中使用Main线程的时候,会提示Module with the Main dispatcher had failed to initialize. For tests Dispatchers.setMain from kotlinx-coroutines-test module can be used,在这里就能捕获到。

outside_default.png

继续往下看:

outside_default.png

接下来就是开启一个协程。

这里通过kotlin的特性重载操作符,直接去它类中找到对应的方法即可。因为此时协程启动模式是DEFAULT,那么直接看block.startCoroutineCancellable(receiver, completion)即可。

接着往下看createCoroutineUnintercepted(receiver, completion)函数,这个函数需要去kotiln官网看,太深了,我没看,我找到了提供给需要的人!源码地址:

https://github.com/JetBrains/kotlin/blob/v1.8.20-Beta/libraries/stdlib/jvm/src/kotlin/coroutines/intrinsics/IntrinsicsJvm.kt

这里看看拦截的方法:

outside_default.png

可以看出,此时就会分发continuation。先来看看不写ContinuationInterceptor是什么效果。

outside_default.png

这段代码写过无数次,因为协程默认启动模式需要调度,所以协程体内的代码还没来得及执行,main函数就已经结束了。

那么在来看看添加协程拦截器后有什么变化。

outside_default.png

可以看出,协程会立即执行,我猜测是拦截的过程中会立即触发恢复,所以才会有这样的效果,可惜的是我没找到恢复的代码。

/   跟随源码手动创建协程   /

刚才看源码的时候看到了这段代码:

outside_default.png

开启一个协程的时候,通过函数扩展。扩展了startCoroutineCancellable。那么我们是否也可以尝试的写一写。

这里有一个注意点:我们并不能调用startCoroutineCancellable因为它是内部方法,我们无法直接调用。

outside_default.png

只能拿createCoroutine来代替,来看看我们的代码:

28c7759d6b0d0b57114ec6e941a7c8c5.png

这里我把范型都替换成了具体的值,否则的话看的更迷糊。

data class TestBean(val message: String)
fun main() {
    fun test(receiver: TestBean, block: suspend TestBean.() -> String) {
            block.createCoroutine(receiver, object : Continuation<String> { // 创建协程
                override val context: CoroutineContext
                    get() = EmptyCoroutineContext

                override fun resumeWith(result: Result<String>) {// 当协程恢复的时候执行
                    println("resume:$result")
                }
            })
    }

    val bean = TestBean("测试数据")

    test(bean) {
        println("我是test内部方法${this}")
        "我是返回数据"
    }
}

代码都写完了,但是这里并没有任何结果!

没有结果是正常现象,因为我们只是创建了一个协程,默认是挂起状态,只有恢复的时候才会执行代码。例如这样:

outside_default.png

如果你觉得这样很麻烦,也可以直接将createCoroutine改为startCoroutine。

  • createCoroutine // 创建协程 [默认挂起]

  • startCoroutine // 直接开启一个协程

outside_default.png

那么我们自定义CoroutineContxt是否还起作用呢?

outside_default.png

这里的时候,我们通过Job#cancel()可以发现,并没有取消协程,恢复代码还是继续执行了。

这是因为当我们使用launch{}开启一个协程的时候,系统帮我们维护了job的各种状态。这里很简单,我们自己维护job即可。

outside_default.png

系统代码指定是没有这么简单,不过模拟一下就可以了,没必要太纠结。那如果是异常如何捕获呢?

outside_default.png

需要注意的是,通过CoroutineExceptionHandler捕获异常,这里监听的是 resumeWith方法。

outside_default.png

只需要再次向上throw一下即可。

/   简单的   /

刚才我们介绍的是有receiver的startCoroutine,还有一个没有receiver的。

outside_default.png

直接来看代码:

outside_default.png

这段代码很简单,只是创建一个普通的协程并恢复,当然也可以通过CoroutineContext来控制协程,上面已经提到了,这里就不重复了。有创建协程手动恢复,就有直接创建并恢复。

outside_default.png

有receiver和没有receiver的区别也很明显,那就是在suspend方法体中是否有receiver。

/   总结   /

本篇我们阅读了CoroutineScope#launch{},并学习了手动管理协程的4个方法:

  • (suspend R.() -> T).startCoroutine // 有receiver直接恢复协程

  • (suspend R.() -> T).createCoroutine // 有receiver创建协程,需要手动恢复

  • (suspend () -> T).startCoroutine //  没有receiver直接恢复协程

  • (suspend () -> T).createCoroutine // 没有receiver创建协程,需要手动恢复

这四胞胎说实话,是真没啥用,但就是得了解一下...

完整代码地址:

https://gitee.com/lanyangyangzzz/coroutine-project/blob/main/app/src/main/java/com/szj/coroutine/project/jvm/blog6/SafeContinuationTest.kt

推荐阅读:

我的新书,《第一行代码 第3版》已出版!

Kotlin协程开发的基础入门知识

LeakCanary是怎么检测到内存泄露的,看完这篇你就懂了

欢迎关注我的公众号

学习技术或投稿

outside_default.png

outside_default.png

长按上图,识别图中二维码即可关注

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Kotlin协程源码简单聊一聊,浅浅看看表层 的相关文章

随机推荐

  • 公司名称注册,公司名称查询,企业名称注册事项

    公司名称的构成 名称一般由四部分依次组成 行政区划 字号 行业特点 组织形式 登记管辖 工商行政管理机关对企业名称实行分级登记管理 国家工商总局登记管辖范围 一 冠以 中国 中华 全国 国家 国际 字样的 二 在名称中间使用 中国 中华 全
  • Python中的三引号''' '''的用法

    链接 https blog csdn net GreenHandCGL article details 79703863
  • ERP仓库管理的操作与设计--开源软件诞生20

    赤龙ERP库房管理讲解 第20篇 用日志记录 开源软件 的诞生 点亮星标 祈盼着一个鼓励 博主开源地址 码云 https gitee com redragon redragon erp GitHub https github com red
  • minkwindow安装

    装库要记住三件事 官网 csdn 耐心 装库太慢就边看剧边装 不要影响心态 首先上官网 GitHub NVIDIA MinkowskiEngine Minkowski Engine is an auto diff neural networ
  • 国产超低功耗华大单片机HC32L136开发板上手入门

    今天介绍下国产超低功耗华大单片机HC32L136开发板上手后的入门操作 开发板可以在华大MCU应用交流群 164973950 免费申请 HC32L136开发板 如下图所示 分为板载调试模块 左半部分 和MCU开发电路 右半部分 二者中间通过
  • 当你的sklearn用不了mean_absolute_percentage_error函数

    今天将一份写好的python机器学习程序换了个电脑跑的时候 出现了如下报错 ImportError cannot import name mean absolute percentage error from sklearn metrics
  • 解决K8s安装中节点初始化时 [kubelet-check] The HTTP call equal to ‘curl -sSL http://localhost:10248/healthz‘ 问题.

    问题描述 安装K8s时 在节点初始化过程中出现 kubelet check The HTTP call equal to curl sSL http localhost 10248 healthz failed with error Get
  • WINDOWS 10 设置WSL 2

    确保已安装 WSL 可以在此处找到相关说明 并且运行的是 Windows 10内部版本 18917或更高版本 可以通过在 PowerShell 中运行以下命令来执行此操作 PowerShell dism exe online enable
  • 分布式深度学习part1:神经网络的分布式训练

    这篇文章是关于神经网络分布式训练的三部系列文章中的第一篇 在第1部中 我们将了解如何通过GPU上的分布式计算显著地加速深度学习模型的训练 并讨论一些挑战并调查当前关于该主题的研究 我们还将考虑神经网络的分布式训练是否适用于特定用例 介绍 在
  • stm32关于通用定时器的周期、频率计算公式

    以下内容针对正点原子的定时器中断实验 定时器时基单元包含 计数器寄存器 TIMx CNT 预分频器寄存器 TIMx PSC 该寄存器用设置对时钟进行分频 然后提供给计数器 作为计数器的时钟 自动装载寄存器 TIMx ARR 定时器的时钟来源
  • 【适合小白】开发一个区块链应用

    前言 本篇教程是小编基于FISCO BCOS官网的教程撰写的 有不明白的地方也可以去官网上的教程看看 在开发区块链应用之前 首先得完成搭建第一个区块链应用 目的是为了搭建节点跟启动控制台 1 了解应用需求 区块链天然具有防篡改 可追溯等特性
  • MQTT协议学习

    MQTT协议是目前物联网最主要的协议 它的设计主要是运用于 低带宽 低网速 差网络环境能够保证数据的正常传输 MQTT协议基于TCP IP协议 运用订阅发布模式 解除应用之间的耦合关系 客户端与客户端之间只需要知道服务器位置 就可以传输数据
  • Github管理项目代码相关git命令

    1 Git global setup git config global user name username git config global user email user email 2 Create a new repositor
  • .classpath .project ch2.iml这三个文件如何理解?

    这三个文件通常出现在Java开发中使用的集成开发环境 IDE 项目中 如Eclipse或IntelliJ IDEA 它们在项目的组织和配置方面发挥着重要的作用 classpath 文件 classpath 是 Eclipse 项目的配置文件
  • Wireshark使用小心得

    Wireshark工作使用小结 基本概念 wireshark是个开源的好用软件 用来分析数据包 数据包 通常就是四层信息 物理层数据帧 数据链路层以太帧头部 网络层IP包头部 传输层TCP包头部 最后就是应用层信息 基础功能使用 打开软件界
  • 范数介绍及C++/OpenCV/Eigen的三种实现

    有时我们需要衡量一个向量的大小 在机器学习中 我们经常使用被称为范数 norm 的函数衡量向量大小 形式上 Lp范数定义如下 范数 包括Lp范数 是将向量映射到非负值的函数 直观上来说 向量x的范数衡量从原点到点x的距离 更严格地说 范数是
  • 失业的程序员(五):商战之前

    本系列前章 失业的程序员 一 二 三 四 一 关于裸奔 早几年出现了很多新名词 如裸婚 蜗居 蚁族 而像我们这种没背景 没后台 没资金的程序员创业那简直可以称为裸奔 创业是否成功的标准实在太多 不能只拿钱来衡量因为很多人会说你铜臭 不能只拿
  • MYSQL的存储过程

    存储过程 存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合 调用存储过程可以简化应用开发人员的很多工作 减少数据在数据库和应用服务器之间的传输 对于提高数据处理的效率是有好处的 存储过程思想上很简单 就是数据库 SQL 语言
  • IAR编译器问题的总结

    之前做项目都是用keil编译器比较多 也基本上用得很顺手 但是最近又开始用IAR编译器 结果这次真是被它折磨得快要崩溃 现在把问题总结如下 IAR编译器版本 IAR2 10 4 IAR编译器默认的优化设置一定要注意 这个是之前做的一个项目
  • Kotlin协程源码简单聊一聊,浅浅看看表层

    今日科技快讯 近日 经历了一次停办 两次规模严重缩水之后 2023年世界移动通信大会 MWC 终于再现往日盛况 有来自200多个国家和地区的2000多家厂商参加 并在此次展会上发布了最新的产品与科技 仅中国就有100余家厂商参展 每年的MW