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

这篇具有很好参考价值的文章主要介绍了Kotlin协程的JVM实现源码分析(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文从协程的启动launch源码入手分析,协程JVM实现分为两篇:

  1. 协程启动和执行源码分析
  2. 无栈协程 和 Continuation

基本环境:

  • IntelliJ IDEA 2023.3.2
  • Kotlin 1.8.20
  • kotlinx-coroutines-core 1.7.3
  • gradle 8.2

一、协程的启动和执行

GlobalScope.launch 启动协程分析:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

调用关系:CoroutineScope.launch -> StandaloneCoroutine.start ->
CoroutineStart.invoke -> block.startCoroutineCancellable

1. startCoroutineCancellable 启动流程

启动协程,默认 执行 block.startCoroutineCancellable 扩展方法:

internal fun <R, T> (suspend (R) -> T).startCoroutineCancellable(
    receiver: R, completion: Continuation<T>,
    onCancellation: ((cause: Throwable) -> Unit)? = null
) =
    runSafely(completion) {
        createCoroutineUnintercepted(receiver, completion).intercepted().resumeCancellableWith(Result.success(Unit), onCancellation)
    }

说明:

  1. createCoroutineUnintercepted, 创建 Continuation;
  2. intercepted,拦截生成 DispatchedContinuation;
  3. resumeCancellableWith,调度器 派发 执行协程。
intercepted()

关键在 intercepted() 方法:

  • 获取 ContinuationInterceptor,默认值是 Dispatchers.Default,
  • 使用 CoroutineDispatcher.interceptContinuation 生成 DispatchedContinuation
// ContinuationImpl 拦截方法
@Transient
private var intercepted: Continuation<Any?>? = null

public fun intercepted(): Continuation<Any?> =
    intercepted
        ?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this)
            .also { intercepted = it }

// Dispatchers.Default 源码
public final override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
    DispatchedContinuation(this, continuation)
resumeCancellableWith

DispatchedContinuation.resumeCancellableWith 实现了 调度器(线程池)的任务 派发,也就是 Runnable

inline fun resumeCancellableWith(
    result: Result<T>,
    noinline onCancellation: ((cause: Throwable) -> Unit)?
) {
    val state = result.toState(onCancellation)
    if (dispatcher.isDispatchNeeded(context)) {
        _state = state
        resumeMode = MODE_CANCELLABLE
        dispatcher.dispatch(context, this)
    } else {
        executeUnconfined(state, MODE_CANCELLABLE) {
            if (!resumeCancelled(state)) {
                resumeUndispatchedWith(result)
            }
        }
    }
}

默认执行到
dispatcher.dispatch(context, this),此时调度器 派发 执行。
DispatchedContinuation 实现了 Runnable 接口, run() 调用即开始执行阶段,接下来分析。

2. DispatchedContinuation

DispatchedContinuation 继承 DispatchedTask,委托了 Contanuation

协程的最终执行:

DispatchedContinuation.resumeCancellableWith -> dispatcher.dispatch()
-> DispatchedTask.run() -> DispatchedContinuation.continuation.resumeWith

最终 DispatchedContinuation.continuation 也就是我们 launch {} 块生成的 SuspendLambda 类对象。

ContinuationImpl

无论是 launch {} 块生成的 SuspendLambda类,还是 suspend fun 函数 生成 ContinuationImpl 匿名类。
它们都 继承 BaseContinuationImpl

基类 BaseContinuationImpl,实现了 resumeWith

try {
    val outcome = invokeSuspend(param)
    if (outcome === COROUTINE_SUSPENDED) return
    Result.success(outcome)
} catch (exception: Throwable) {
    Result.failure(exception)
}

调用了 抽象 invokeSuspend,也就是 launch {} 块编译后的代码。

执行完成后,会执行 协程 completion.resumeWith(outcome),最终完成。

resumeWith -> onCompletionInternal -> onCompleted 或 onCancelled

launch {} 块编译代码分析

launch {}async {} 编译后,都继承 SuspendLambda

反编译.class,通过 jadx-gui 看到 块 代码一般是下面 形式:

public static final class AnonymousClass1 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Unit>, Object> {
    int label;

    @NotNull
    public final Continuation<Unit> create(@Nullable Object value, @NotNull Continuation<?> continuation) {
        return new AnonymousClass1(continuation);
    }

    @Nullable
    public final Object invoke(@NotNull CoroutineScope p1, @Nullable Continuation<? super Unit> continuation) {
        return create(p1, continuation).invokeSuspend(Unit.INSTANCE);
    }

    @Nullable
    public final Object invokeSuspend(@NotNull Object $result) {
        // launch {} 执行代码块 逻辑,会编译到这里
        ...
    }
}

小结

通过launch启动协程源码分析,了解了:文章来源地址https://www.toymoban.com/news/detail-805562.html

  • Dispatchers 调度器何时派发任务
  • 协程 Continuation 挂起、执行 和 恢复

补充类图

Continuation

DispatchedContinuation

关键类和文件

  1. kotlin.coroutines.Continuation.kt
  2. kotlin.coroutines.CoroutineContext
  3. kotlin.coroutines.jvm.internal.BaseContinuationImpl.kt 对应 Continuation 默认实现。
  4. kotlinx.coroutines.CoroutineStart 启动线程方式、调用

文档

  • kotlin coroutines
  • kotlin KEEP | Offcial
  • Advanced coroutines concepts | Android
  • 分析Kotlin协程实现原理
  • 探索 Kotlin 协程原理
  • KotlinConf 2017 - Deep Dive into Coroutines on JVM
  • Koltin 协程(非阻塞式挂起)实现原理(五)
  • kotlinx-coroutines-core 1.7.3源码
  • https://doordash.engineering/2021/11/09/the-beginners-guide-to-kotlin-coroutine-internals/
  • CancellableContinuationImpl.kt

到了这里,关于Kotlin协程的JVM实现源码分析(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入分析 Java、Kotlin、Go 的线程和协程

    Go 语言比 Java 语言性能优越的一个原因,就是轻量级线程 Goroutines (协程Coroutine)。本篇文章深入分析下 Java 的线程和 Go 的协程。 协程并不是 Go 提出来的新概念,其他的一些编程语言,例如:Go、Python 等都可以在语言层面上实现协程,甚至是 Java,也可以通过使用扩展库来

    2024年02月01日
    浏览(40)
  • Plugin [id: ‘org.jetbrains.kotlin.jvm‘, version: ‘1.8.21‘] was not found

    使用最新的 Intellij IDEA 创建一个可以运行 kotlin 的代码环境,默认创建 Main.kt 文件。 下面是默认生成的 build.gradle.kts 文件 编译直接报错: 更换IDEA版本(因为在很久之前学习 kotlin 的时候没有这么费劲, IDEA 直接支持),结果无效(PS:尝试过高低版本都不行); 添加电脑的

    2024年02月09日
    浏览(49)
  • 【kotlin 协程】万字协程 一篇完成kotlin 协程进阶

    Kotlin 中的协程提供了一种全新处理并发的方式,可以在 Android 平台上使用它来简化异步执行的代码。协程是从 Kotlin 1.3 版本开始引入,但这一概念在编程世界诞生的黎明之际就有了,最早使用协程的编程语言可以追溯到 1967 年的 Simula 语言。 在过去几年间,协程这个概念发展

    2024年02月07日
    浏览(52)
  • Kotlin 协程一 —— 协程 Coroutine

    1.1.1基本定义 进程 进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。 进程是资源分配的最小单位,在单核CPU中,同一时刻只有一个程序在内存中被CPU调用运行。 线程 基本的

    2024年02月05日
    浏览(49)
  • kotlin语法进阶 - 协程(一)协程基础

    协程并不是一个新的概念,而是一个非常老的概念,很多语言都支持协程,建议去浏览器去了解一下协程的历史和基本概念,这里我们只讲一下kotlin中的协程的作用。 从代码实现角度来看:kotlin协程底层是用线程实现的,是一个封装完善供开发者使用的线程框架。kotlin的一个

    2024年02月09日
    浏览(45)
  • Kotlin协程-从一到多

    上一篇文章,我介绍了Kotlin协程的创建,使用,协作等内容。本篇将引入更多的使用场景,继续带你走进协程世界。 常用编程语言都会内置对同一类型不同对象的数据集表示,我们通常称之为容器类。不同的容器类适用于不同的使用场景。Kotlin的 Flow 就是在异步计算的需求下

    2024年02月09日
    浏览(55)
  • Kotlin协程学习之-02

    协程的基本使用 GlobalScope.launch 生命周期与进程一致,且无法取消 runBlocking 会阻塞线程,一般在测试阶段可以使用 val coroutineScope = CoroutineScope(context) coroutineScope.launch 通过context参数去管理和控制协程的生命周期 用法 val coroutineScope = CoroutineScope(context) coroutineScope.launch(Dispatche

    2024年01月22日
    浏览(44)
  • Kotlin 协程 - 多路复用 select()

            又叫选择表达式,是一个挂起函数,可以同时等待多个挂起结果,只取用最快恢复的那个值(即多种方式获取数据,哪个更快返回结果就用哪个)。         同时到达 select() 会优先选择先写子表达式,想随机(公平)的话使用 selectUnbiased() 替换 。         能

    2024年02月10日
    浏览(45)
  • Kotlin协程-从理论到实战

    上一篇文章从理论上对Kotlin协程进行了部分说明,本文将在上一篇的基础上,从实战出发,继续协程之旅。 在Kotlin中,要想使用协程,首先需要使用协程创建器创建,但还有个前提——协程作用域( CoroutineScope )。在早期的Kotlin实现中,协程创建器是一等函数,也就是说我们随

    2024年02月09日
    浏览(42)
  • Android Kotlin 协程初探

    维基百科:协程,英文Coroutine [kəru’tin] (可入厅),是计算机程序的一类组件,推广了协作式多任务的子程序,允许执行被挂起与被恢复。 作为Google钦定的Android开发首选语言Kotlin,协程并不是 Kotlin 提出来的新概念,目前有协程概念的编程语言有Lua语言、Python语言、Go语言

    2024年02月08日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包