Sintaxis avanzada de Kotlin: rutina (2) Principio de función de suspensión

Hay muchos principios de suspensión de funciones en Internet, pero son demasiado profundos o los ejemplos son demasiado complicados, lo cual es muy hostil para los principiantes. Como principiante ideal, usaré el ejemplo más simple para que todos comprendan la función de suspensión. en unos minutos El principio de funcionamiento.

La función modificada por la palabra clave suspender se llama función de suspensión, que literalmente significa una función que se puede suspender. La suspensión puede entenderse como suspensión y se puede reanudar si se puede suspender.
Entonces, ¿cómo implementa la función de suspensión la suspensión y reanudación del código?

De la siguiente manera: definimos una función de suspensión a voluntad y luego usamos Android Studio para descompilar Kotlin en código Java. (Pasos para descompilar: Herramientas->Kotlin->Mostrar código de bytes de Kotlin->Descompilar)

suspend fun getInfo() : String {
    
    
    delay(1000L)
    Log.e("---" , "延迟后执行的代码")
    return "hello world!"
}

Después de la descompilación, es el siguiente: omita el código en el método por ahora

public final Object getInfo(@NotNull Continuation var1) {
    
    ...
}

Como puede ver, el código descompilado tiene un parámetro de Continuación adicional y el valor de retorno se convierte en Objeto. Echemos un vistazo a Continuación. La siguiente es una interfaz, con un atributo de interfaz de CoroutineContext y un método de interfaz de resumeWith.

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>)
}

De las notas de traducción, puede saber que la función de resumeWith es continuar ejecutando la corrutina correspondiente y pasar el resultado de éxito o fracaso como valor de retorno del último punto de pausa.
Entonces: la continuación es en realidad una interfaz de devolución de llamada con parámetros genéricos. Este proceso de convertir una función de suspensión en una función de devolución de llamada se llama: transformación CPS (transformación de estilo de paso continuo)

Entonces, ¿qué hace esta interfaz de devolución de llamada?
Veamos el código descompilado completo:

@Nullable
public final Object getInfo(@NotNull Continuation var1) {
    
    
   Object $continuation;
   label20: {
    
    
      if (var1 instanceof <undefinedtype>) {
    
    
         $continuation = (<undefinedtype>)var1;
         if ((((<undefinedtype>)$continuation).label & Integer.MIN_VALUE) != 0) {
    
    
            ((<undefinedtype>)$continuation).label -= Integer.MIN_VALUE;
            break label20;
         }
      }

      $continuation = new ContinuationImpl(var1) {
    
    
         // $FF: synthetic field
         Object result;
         int label;

         @Nullable
         public final Object invokeSuspend(@NotNull Object $result) {
    
    
            this.result = $result;
            this.label |= Integer.MIN_VALUE;
            return ThirdActivity.this.getInfo(this);
         }
      };
   }

   Object $result = ((<undefinedtype>)$continuation).result;
   Object var4 = IntrinsicsKt.getCOROUTINE_SUSPENDED();
   switch(((<undefinedtype>)$continuation).label) {
    
    
   case 0:
      ResultKt.throwOnFailure($result);
      ((<undefinedtype>)$continuation).label = 1;
      if (DelayKt.delay(1000L, (Continuation)$continuation) == var4) {
    
    
         return var4;
      }
      break;
   case 1:
      ResultKt.throwOnFailure($result);
      break;
   default:
      throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
   }

   Log.e("---", "延迟后执行的代码");
   return "hello world!";
}

El código parece muy desordenado, analicémoslo paso a paso:

  1. El método getInfo recibe un objeto de Continuación, que se sabe que es una interfaz de devolución de llamada y se utiliza para llamar cuando se reanuda la rutina.
  2. La Continuación está encapsulada en un objeto ContinuationImpl $continuation
    . El objeto también tiene una etiqueta de bandera, que inicialmente es igual a 0, y tiene un método invokeSuspend(), que llamará al método getInfo, ¿eh? La llamada volvió. ¡Parece que esto se usa para restaurar el código!
  3. El siguiente código resulta ser un caso de cambio. Echemos un vistazo a este caso de cambio por separado. Divide el código en dos partes de acuerdo con el valor de la etiqueta de $continuación. Cuando el estado = 0, se ejecuta el retardo de la función de suspensión y $ continuación se pasa a Se utiliza el método de retraso, la etiqueta se cambia a 1 y luego se devuelve directamente sin ejecutar el código posterior. Entonces, ¿qué pasará a continuación? Cuando se complete el método de retardo, se llamará al método invokeSuspend() de $continuación, que a su vez llamará al método getInfo para restaurar el código, pero en este momento el valor de la etiqueta de $continuación es Ya es 1, cambie de caso. Ingresará el juicio de 1 y continuará ejecutando el siguiente código.
    Entonces, el proceso general es muy claro: dividimos el código en dos partes (antes de la suspensión y después de la suspensión) a través de la máquina de estado, y luego usamos la interfaz de devolución de llamada para regresar y ejecutar la función original nuevamente después de ejecutar la función de suspensión. pero debido a que la máquina de estado El estado ha cambiado, solo podemos ejecutar el código después de la suspensión.

Por lo tanto: la esencia de la función de suspensión es la interfaz de devolución de llamada CallBack + máquina de estado (caso de cambio + valor de estado para implementar la ejecución de segmentación de código)

Pensemos en ello de nuevo. Hemos segmentado el código. Podemos agregar cambio de subprocesos en función de la segmentación del código. Esto no es excesivo.
Pensemos en ello de nuevo. La función de suspensión utiliza una interfaz de devolución de llamada. Podemos agregar anidamiento o paralelismo según la interfaz de devolución de llamada. Esto no es excesivo.
¿No se ampliaría la realización de esta idea y función del código? Puede ver más métodos proporcionados al descompilar corrutinas de Kotlin para verificar varias ideas.

Se puede ver que la capa inferior de la rutina de Kotlin ha hecho mucho por nosotros, permitiéndonos a los desarrolladores implementar funciones complejas de la manera más simple, lo que también es una ventaja de la rutina de Kotlin.

Este artículo se utiliza principalmente para comprender rápidamente el principio de suspensión de funciones. Debe haber algunas cosas inapropiadas en él. Espero que todos puedan corregirme.

Supongo que te gusta

Origin blog.csdn.net/weixin_43864176/article/details/126373256
Recomendado
Clasificación