Kotlin协程是一套基于Java Thread的线程框架,最大的特点就是可以1,用同步的方式写出异步代码,并且2,不阻塞当前线程。
基本原理:
cas转换+状态机,协程体会被编译成一个SuspendLambda的子类,在这个类的invokeSuspend方法中,协程体中的suspend方法会被分割到switch不同的分支中,每个suspend方法会被cps机制转换成带有一个Continuation参数的方法。
通过一个label标签控制分支代码执行,label为0,首先会进入第一个分支,首先将label设置为下一个分支的数值,然后执行第一个suspend方法并传递当前Continuation,得到返回值,如果是COROUTINE_SUSPENDED,协程框架就直接return,协程挂起,当第一个suspend方法执行完成,会回调Continuation的invokeSuspend方法,进入第二个分支执行,以此类推执行完所有suspend方法。
调用原理。
协程一般是通过launch启动,启动过程中会构建三个关键对象
1,第一层协程对象AbstractCoroutine子类,主要处理协程状态和外层协程的恢复。
2,第二层对象BaseContinuationImpl子类,由编译器将我们的luanch代码转换而成,在其resumeWith方法中通过调用invokeSuspend()执行我们的任务代码。并代理第一层对象。
3,第三层对象DispatchedContinuation,会代理第二层协程对象,并持有我们传入的dispatcher,主要作用是负责协程的线程调度。
在DispatchedContinuation 的resume方法中,会通过dispatcher将协程切换到指定的线程中去执行,实际就是执行一个runnable任务,在这个runnable任务中调用了,第二层对象BaseContinuationImpl子类的resumewith方法,在这个方法中调用了invokeSuspend()执行我们的具体的代码,当执行到一个suspend方法时,会获取到一个结果,如果是crotinesuspend,就return,外层协程挂起。
suspend方法中一般使用withcontext去执行子任务,在withcontext方法中会先创建一个dispathedCoroutine,这也是AbstractCoroutine子类,创建的时候会传入外层协程的第二层对象,用于外层协程恢复,然后开启协程去执行任务,这个过程是和launch开启协程的过程是一样的。开启协程之后会调用getresult方法,获取结果,如果协程没有运行完成,就返回crotinesuspend,
withcontext去执行完任务之后,会调用到它里面的第一层协程对象,dispathedCoroutine的reumewith方法,在这个方法中,会使用它持有的外层协程的BaseContinuationImpl的子类,获取外层协程的DispatchedContinuation,然后用这个DispatchedContinuation将运行过程切换到外层协程的线程中去。再次调用外层协程的BaseContinuationImpl的resumewith方法,再次调用invokesuspend方法,那么这个流程就再次切换到外层协程的执行流程了。
我们拍摄视频之后需要上传,上传的资源有三个,第一个是视频,第二个是视频封面,第三个是封面动图。为了节省上传时间,这里我们采用协程的async方法,将三个资源并发上传,然后用一个triple对象包装这个三个async任务对应的await方法,去得到三个资源上传后的url,然后协程就会等所有资源上传成功后,才会将这个triple对象返回给我们。
他的原理是,协程体被编译成一个SuspendLambda的子类,在这个类的invokeSuspend方法中,里面是一个lable控制的switch分支,每次执行协程对应的await前会将lable+1。首先lable为0
进入第0个case,,使用async先开启协程1,协程2,然后调用协程1的await,传递当前的continuation,然后从awiat获取结果,如果是COROUTINE_SUSPENDED,协程框架就直接return,协程挂起,当协程1执行完成,会回调传递给它的Continuation的invokeSuspend方法,进入case1分支,得到协程1的结果v1,然后调用协程2的await,如果协程2没执行完,同样外层协程挂起,协程2执行完成后进入case2,得到协程2的结果v2,跳出switch,然后将v1和v2合并。
之所以协程能挂起恢复设计到协程的运行过程。