Skip to content

Latest commit

 

History

History
82 lines (47 loc) · 3.14 KB

协程实现原理.md

File metadata and controls

82 lines (47 loc) · 3.14 KB

1.什么是协程?

协程是一种非抢占式(协作式)的任务调度模式,程序可以主动挂起或者恢复执行。Kotlin 协程的核心竞争力在于:它能简化异步并发任务,以同步方式写异步代码。

2.协程与线程的区别

协程基于线程,但相对于线程轻量很多。可以理解为在用户层模拟线程操作;

线程的上下文切换涉及到用户态和内核态的切换,而协程的上下文切换完全是在用户态控制的,避免了大量的中断参与,减少了线程上下文切换与调度的资源消耗

CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再次加载这个任务的状态,从任务保存到再加载的过程就是一次上下文切换

3.kotlin中的协程

Kotlin在语言级别并没有实现一种同步机制(锁),还是依靠Kotlin-JVM的提供的Java关键字(如synchronized),即锁的实现还是交给线程处理 因而Kotlin协程本质上只是一套基于原生Java线程池 的封装。

Kotlin 协程的核心竞争力在于:它能简化异步并发任务,以同步方式写异步代码。 下面介绍一些kotin协程中的基本概念

4.挂起函数

使用suspend关键字修饰的函数叫做挂起函数,挂起函数只能在协程内或其他挂起函数内使用。

协程内部挂起函数的调用处被称为挂起点,挂起点如果出现异步调用就会挂起当前协程,知道对应的continuation的resume函数被调用才会恢复执行。

suspend

5.suspend原理

suspend 的本质,就是 CallBack

suspend fun getUserInfo(): String {
    withContext(Dispatchers.IO) {
        delay(1000L)
    }
    return "BoyCoder"
}

将挂起函数的字节码反编译成java代码简化后得到如下结果:

public final Object getUserInfo(@NotNull Continuation var1) {


   return "BoyCoder";
}
public interface Continuation<in T> {

    public val context: CoroutineContext

    public fun resumeWith(result: Result<T>)
}

可以看到,编译器会给挂起函数添加一个Continuation参数,这被称为CPS 转换(Continuation-Passing-Style Transformation)

suspend函数不能在协程体外调用的原因也可以知道了,就是因为这个Continuation实例的传递。

动画演示挂起函数CPS转换过程:

cps

  1. 增加了Continuation类型的参数
  2. 返回类型从String转变成了Any

CPS 转换,其实就是将原本的同步挂起函数转换成CallBack 异步代码的过程。 这个转换是编译器在背后做的,我们对此无感知。

continuation

参考链接:https://juejin.cn/post/6973650934664527885