zoukankan      html  css  js  c++  java
  • 协程及Kotlin协程

    一、协程是什么?

    协程是程序自己控制挂起和恢复的程序。

    协程可以实现多任务协作执行。

    二、协程作用?

    • 协程可以让异步代码同步化。
    • 协程可以降低异步程序的设计复杂度。

    三、协程分类

    • 按调用栈分类:

      • 有栈协程:每个协程都会分配一个单独调用栈,类似于线程的调用栈。
      • 无栈协程:协程不会分配一个单独调用栈,挂起点的状态通过闭包和对象保存。
    • 按调用关系分类:

      • 对称协程:协程调用权可以转移给任意协程,协程之间是对等关系。比如:协程A调度协程B,协程B调度协程C,协程C调度协程A。
      • 非对称协程:调度权只能转移给调度自己的协程,协程存在父子关系。

    四、Kotlin中协程

    Kotlin实现的协程是无栈协程,挂起状态通过Continuation保存,CoroutineContext包含一个协程调度器。

    1. 挂起函数及suspend修饰符

    通过suspend修饰的函数就是挂起函数。

    挂起函数只能通过其它挂起函数或者协程调用。

    挂起函数调用时包含了协程的挂起语义。 

    Continuation源码:

      1 /**
      2  * Interface representing a continuation after a suspension point that returns a value of type `T`.
      3  */
      4 @SinceKotlin("1.3")
      5 public interface Continuation<in T> {
      6     /**
      7      * The context of the coroutine that corresponds to this continuation.
      8      */
      9     public val context: CoroutineContext
     10 
     11     /**
     12      * Resumes the execution of the corresponding coroutine passing a successful or failed [result] as the
     13      * return value of the last suspension point.
     14      */
     15     public fun resumeWith(result: Result<T>)
     16 }
     17 
     18 /**
     19  * Classes and interfaces marked with this annotation are restricted when used as receivers for extension
     20  * `suspend` functions. These `suspend` extensions can only invoke other member or extension `suspend` functions on this particular
     21  * receiver and are restricted from calling arbitrary suspension functions.
     22  */
     23 @SinceKotlin("1.3")
     24 @Target(AnnotationTarget.CLASS)
     25 @Retention(AnnotationRetention.BINARY)
     26 public annotation class RestrictsSuspension
     27 
     28 /**
     29  * Resumes the execution of the corresponding coroutine passing [value] as the return value of the last suspension point.
     30  */
     31 @SinceKotlin("1.3")
     32 @InlineOnly
     33 public inline fun <T> Continuation<T>.resume(value: T): Unit =
     34     resumeWith(Result.success(value))
     35 
     36 /**
     37  * Resumes the execution of the corresponding coroutine so that the [exception] is re-thrown right after the
     38  * last suspension point.
     39  */
     40 @SinceKotlin("1.3")
     41 @InlineOnly
     42 public inline fun <T> Continuation<T>.resumeWithException(exception: Throwable): Unit =
     43     resumeWith(Result.failure(exception))
     44 
     45 
     46 /**
     47  * Creates a [Continuation] instance with the given [context] and implementation of [resumeWith] method.
     48  */
     49 @SinceKotlin("1.3")
     50 @InlineOnly
     51 public inline fun <T> Continuation(
     52     context: CoroutineContext,
     53     crossinline resumeWith: (Result<T>) -> Unit
     54 ): Continuation<T> =
     55     object : Continuation<T> {
     56         override val context: CoroutineContext
     57             get() = context
     58 
     59         override fun resumeWith(result: Result<T>) =
     60             resumeWith(result)
     61     }
     62 
     63 /**
     64  * Creates a coroutine without a receiver and with result type [T].
     65  * This function creates a new, fresh instance of suspendable computation every time it is invoked.
     66  *
     67  * To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance.
     68  * The [completion] continuation is invoked when the coroutine completes with a result or an exception.
     69  * Subsequent invocation of any resume function on the resulting continuation will produce an [IllegalStateException].
     70  */
     71 @SinceKotlin("1.3")
     72 @Suppress("UNCHECKED_CAST")
     73 public fun <T> (suspend () -> T).createCoroutine(
     74     completion: Continuation<T>
     75 ): Continuation<Unit> =
     76     SafeContinuation(createCoroutineUnintercepted(completion).intercepted(), COROUTINE_SUSPENDED)
     77 
     78 /**
     79  * Creates a coroutine with receiver type [R] and result type [T].
     80  * This function creates a new, fresh instance of suspendable computation every time it is invoked.
     81  *
     82  * To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance.
     83  * The [completion] continuation is invoked when the coroutine completes with a result or an exception.
     84  * Subsequent invocation of any resume function on the resulting continuation will produce an [IllegalStateException].
     85  */
     86 @SinceKotlin("1.3")
     87 @Suppress("UNCHECKED_CAST")
     88 public fun <R, T> (suspend R.() -> T).createCoroutine(
     89     receiver: R,
     90     completion: Continuation<T>
     91 ): Continuation<Unit> =
     92     SafeContinuation(createCoroutineUnintercepted(receiver, completion).intercepted(), COROUTINE_SUSPENDED)
     93 
     94 /**
     95  * Starts a coroutine without a receiver and with result type [T].
     96  * This function creates and starts a new, fresh instance of suspendable computation every time it is invoked.
     97  * The [completion] continuation is invoked when the coroutine completes with a result or an exception.
     98  */
     99 @SinceKotlin("1.3")
    100 @Suppress("UNCHECKED_CAST")
    101 public fun <T> (suspend () -> T).startCoroutine(
    102     completion: Continuation<T>
    103 ) {
    104     createCoroutineUnintercepted(completion).intercepted().resume(Unit)
    105 }
    106 
    107 /**
    108  * Starts a coroutine with receiver type [R] and result type [T].
    109  * This function creates and starts a new, fresh instance of suspendable computation every time it is invoked.
    110  * The [completion] continuation is invoked when the coroutine completes with a result or an exception.
    111  */
    112 @SinceKotlin("1.3")
    113 @Suppress("UNCHECKED_CAST")
    114 public fun <R, T> (suspend R.() -> T).startCoroutine(
    115     receiver: R,
    116     completion: Continuation<T>
    117 ) {
    118     createCoroutineUnintercepted(receiver, completion).intercepted().resume(Unit)
    119 }
    120 
    121 /**
    122  * Obtains the current continuation instance inside suspend functions and suspends
    123  * the currently running coroutine.
    124  *
    125  * In this function both [Continuation.resume] and [Continuation.resumeWithException] can be used either synchronously in
    126  * the same stack-frame where the suspension function is run or asynchronously later in the same thread or
    127  * from a different thread of execution. Subsequent invocation of any resume function will produce an [IllegalStateException].
    128  */
    129 @SinceKotlin("1.3")
    130 @InlineOnly
    131 public suspend inline fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T =
    132     suspendCoroutineUninterceptedOrReturn { c: Continuation<T> ->
    133         val safe = SafeContinuation(c.intercepted())
    134         block(safe)
    135         safe.getOrThrow()
    136     }
    137 
    138 /**
    139  * Returns the context of the current coroutine.
    140  */
    141 @SinceKotlin("1.3")
    142 @Suppress("WRONG_MODIFIER_TARGET")
    143 @InlineOnly
    144 public suspend inline val coroutineContext: CoroutineContext
    145     get() {
    146         throw NotImplementedError("Implemented as intrinsic")
    147     }

     挂起函数格式:

    suspend fun test(param: Int): String {
       return "test"
    }

    挂起函数类型:

    suspend (param: Int) -> String

    在编译后,解码挂起函数:

    suspend fun test(param: Int, continuation: Continuation<String>): String {
        return "test"
    }

    在函数参数中多了一个Continuation参数,Continuation就是用于保存协程挂起点状态对象。这也是为什么挂起函数只能由其它挂起函数或者协程调用,为什么Kotlin编译器在编译时给挂起函数多加了一个参数。

    2. 挂起与未挂起

    • 真正的挂起:就是必须异步调用resume,包括:1. 切换到其它线程的resume;2. 单线程事件循环异步执行;
    • 未挂起:就是未异步调用resume,直接将结果传递出去。

    PS:在resume时返回值分两类,1. 函数真正的返回值,比如上面test函数,返回值类型为String类型;2. 返回挂起函数的挂起标识;只有返回挂起标识时才是真正的挂起。

    3. 将回调转写成挂起函数:

    • 使用suspendCoroutine获取挂起函数的Continuation;
    • 回调成功分支使用Continuation.resume(value)函数;
    • 回调失败分支使用Continuation.resumeWithException(error)函数;

     4. CoroutineContext 协程上下文包含一个协程调度器。

  • 相关阅读:
    (教程)怎么避免拼多多比价订单行为
    Ubuntu下搭建apache2+GGI环境
    搭建k8s
    我的2021年总结
    工作三年的一些感悟
    xshell6+xftp6免安装破解版
    centos7启动docker容器时提示Error response from daemon: Unknown runtime specified dockerrunc
    解决一个C#中定时任务被阻塞问题
    工程中实际问题解决两例——基于C#
    解决一次gitlab因异常关机导致启动失败
  • 原文地址:https://www.cnblogs.com/naray/p/12993769.html
Copyright © 2011-2022 走看看