Kotlin之Suspend Function

1,862 阅读2分钟

Kotlin之Suspend Function

suspend

kotlin的__suspend__方法是kotlin协程的核心,任何一个方法以__suspend__关键字修饰,则表示该方法支持以__非阻塞__的方式__挂起__和__恢复__方法调用过程。__suspend__方法的定义与普通方法一样,唯一的区别在于只有__suspend__方法才可以调用__suspend__方法。

compile

Kotlin代码:

suspend fun testSuspend1(value: Any?) {
    println("before testSuspend2")
    testSuspend2("2")
    println("after testSuspend2")
}

编译之后的Java代码:

 public static final Object testSuspend1(@Nullable Object value, @NotNull Continuation $completion) {
      Object $continuation = new ContinuationImpl($completion) {
            // $FF: synthetic field
            Object result;
            int label;
            Object L$0;

            @Nullable
            public final Object invokeSuspend(@NotNull Object $result) {
               this.result = $result;
               this.label |= Integer.MIN_VALUE;
               return LearnKotlinKt.testSuspend1((Object)null, this);
            }
         };
      }

      Object $result = ((<undefinedtype>)$continuation).result;
      Object var6 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
      String var2;
      boolean var3;
      switch(((<undefinedtype>)$continuation).label) {
      case 0:
         ResultKt.throwOnFailure($result);
         var2 = "before testSuspend2";
         var3 = false;
         System.out.println(var2);
         ((<undefinedtype>)$continuation).L$0 = value;
         ((<undefinedtype>)$continuation).label = 1;
         if (testSuspend2("2", (Continuation)$continuation) == var6) {
            return var6;
         }
         break;
      case 1:
         value = ((<undefinedtype>)$continuation).L$0;
         ResultKt.throwOnFailure($result);
         break;
      default:
         throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
      }

      var2 = "after testSuspend2";
      var3 = false;
      System.out.println(var2);
      return Unit.INSTANCE;
   }

事实上,__suspend__方法的实现主要在kotlin编译器:

  • 对于任何一个以__suspend__关键字修饰的方法,kotlin在编译的时候都会在该方法中拓展一个参数:Continuation,该参数是方法挂起之后恢复执行的回调。

  • 对于__suspend__方法中调用到的其他__suspend__方法,kotlin在编译的时候会以该方法作为分界点将代码块一分为二,并创建一个匿名内部类__ContinuationImpl__保存方法执行时的变量(保护现场)。

Continuation

/**
 * Interface representing a continuation after a suspension point that returns a value of type `T`.
 */
@SinceKotlin("1.3")
public interface Continuation<in T> {
    /**
     * The context of the coroutine that corresponds to this continuation.
     */
    public val context: CoroutineContext

    /**
     * Resumes the execution of the corresponding coroutine passing a successful or failed [result] as the
     * return value of the last suspension point.
     */
    public fun resumeWith(result: Result<T>)
}

__Continuation__是__suspend__方法挂起之后恢复执行的回调,也是kotlin编译器自动为每个__suspend__方法添加的参数,恢复(回调)的入口点是__resumeWith__方法,其参数为下一层级的__suspend__方法执行结果。

ContinuationImpl

ContinuationImpl__继承自__BaseContinuationImpl,从上文编译之后的代码可以看到,每一个上级__suspend__方法传递进来的__Continuation__都会被封装保存到__ContinuationImpl__中,通过__ContinuationImpl__来控制__suspend__方法恢复(回调)逻辑。

BaseContinuationImpl

// This implementation is final. This fact is used to unroll resumeWith recursion.
    public final override fun resumeWith(result: Result<Any?>) {
        // This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume
        var current = this
        var param = result
        while (true) {
            // Invoke "resume" debug probe on every resumed continuation, so that a debugging library infrastructure
            // can precisely track what part of suspended callstack was already resumed
            probeCoroutineResumed(current)
            with(current) {
                val completion = completion!! // fail fast when trying to resume continuation without completion
                val outcome: Result<Any?> =
                    try {
                        val outcome = invokeSuspend(param)
                        if (outcome === COROUTINE_SUSPENDED) return
                        Result.success(outcome)
                    } catch (exception: Throwable) {
                        Result.failure(exception)
                    }
                releaseIntercepted() // this state machine instance is terminating
                if (completion is BaseContinuationImpl) {
                    // unrolling recursion via loop
                    current = completion
                    param = outcome
                } else {
                    // top-level completion reached -- invoke and return
                    completion.resumeWith(outcome)
                    return
                }
            }
        }
    }

__BaseContinuationImpl__恢复(回调)执行逻辑:

  • 由下往上一级一级恢复(回调)__suspend方法__即调用__invokeSuspend()__方法

  • 如果当前层级的__suspend__方法恢复(回调)之后挂起,则中断恢复(回调)过程

  • 如果当前层级的__suspend__方法恢复(回调)之后未挂起,则封装该返回值并恢复(回调)上一层级的__suspend__方法

  • 如果当前层级的__suspend__方法抛出异常,则catch该异常并恢复(回调)上一层级的__suspend__方法,上一层级的__suspend__方法收到该异常之后将重新抛出该异常,如此层层上传。