Trabajos, Espera, Cancelación en Kotlin Coroutines

Requisito previo:

En este artículo, se discutirán los siguientes temas, como cuáles son los trabajos en una corrutina , cómo esperar la corrutina y cómo cancelar la corrutina. Cada vez que se lanza una nueva rutina, devolverá un trabajo. El trabajo que se devuelve se puede usar en muchos lugares, como se puede usar para esperar a que la rutina haga algún trabajo o se puede usar para cancelar la rutina. El trabajo se puede usar para llamar a muchas funcionalidades como el método join() que se usa para esperar la rutina y el método cancel() que se usa para cancelar la ejecución de la rutina. 

Definición de trabajo

De acuerdo con la documentación oficial, la definición de un trabajo se da de la siguiente manera:

Un trabajo es algo que se puede cancelar con un ciclo de vida que culmina con su finalización. El trabajo de rutina se crea con el generador de rutinas de lanzamiento. Ejecuta un bloque de código específico y se completa al finalizar este bloque.

¿Cómo conseguir el trabajo?

Como se discutió que se devolverá un trabajo cuando se inicie una nueva rutina, ahora veamos mediante programación cómo se devuelve el trabajo y cómo se puede usar.

Kotlin

// sample kotlin program in kotlin
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
 
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
         
        // A job is returned
        val job = GlobalScope.launch(Dispatchers.Default) {
 
        }
    }
}

Cosas que se pueden hacer usando Job

Las corrutinas se pueden controlar a través de las funciones que están disponibles en la interfaz del trabajo. Algunas funciones de las muchas que ofrece la interfaz de trabajo son las siguientes:

  • comienzo()
  • unirse()
  • cancelar()

método join()

La función join() es una función de suspensión, es decir, se puede llamar desde una rutina o desde otra función de suspensión. El trabajo bloquea todos los subprocesos hasta que la rutina en la que está escrito o el contexto termine su trabajo. Solo cuando la corrutina termine, se ejecutarán las líneas después de la función join() . Tomemos un ejemplo que demuestra el funcionamiento de la función join() .

Kotlin

// sample kotlin program for demonstrating job.join method
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.coroutines.*
 
class MainActivity : AppCompatActivity() {
   
    val TAG:String = "Main Activity"
   
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
         
        // creating/launching a coroutine will return the job
        val job = GlobalScope.launch(Dispatchers.Default) {
            repeat(5)
            {
                Log.d(TAG, "Coroutines is still working")
                // delay the coroutine by 1sec
                delay(1000)
            }
        }
 
        runBlocking {
              // waiting for the coroutine to finish it's work
            job.join()
            Log.d(TAG, "Main Thread is Running")
        }
    }
}

La salida del registro es la siguiente:

Las marcas de tiempo se muestran mediante un círculo ovalado

Log Output

Se puede ver que la declaración de registro no puede ejecutarse hasta que la corrutina que se está ejecutando finalice su trabajo y posiblemente solo se deba al método join() .

Cancelar() Método

El método cancel() se usa para cancelar la rutina, sin esperar a que termine su trabajo. Se puede decir que es justo lo opuesto al método join, en el sentido de que el método join() espera a que la corrutina termine todo su trabajo y bloquee todos los demás subprocesos, mientras que el método cancel() , cuando se encuentra, elimina el coroutine es decir, detiene el coroutine. Tomemos un ejemplo que demuestra el funcionamiento de la función cancel() .

Kotlin

// sample kotlin program
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.coroutines.*
 
class MainActivity : AppCompatActivity() {
   
    val TAG:String = "Main Activity"
   
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        val job = GlobalScope.launch(Dispatchers.Default) {
            repeat(5)
            {
                Log.d(TAG, "Coroutines is still working")
                delay(1000)
            }
        }
 
        runBlocking {
              // delaying the coroutine by 2sec
            delay(2000)
             
            // canceling/stopping  the coroutine
            job.cancel()
            Log.d(TAG, "Main Thread is Running")
        }
    }
}

La salida del registro es la siguiente:

Las marcas de tiempo se muestran mediante un círculo ovalado

Log Output

Cancelar una rutina no siempre es más fácil como en el ejemplo anterior. Se debe recordar que cuando alguien está usando el método cancel() , coroutine debe saber que se encontrará el método cancel, es decir, podría suceder que se haya encontrado el método cancel y coroutine aún se esté ejecutando. En resumen, debe haber suficiente tiempo para decirle a la rutina que ha sido cancelada. La función de retraso() dentro de la función de repetición asegura que la rutina tenga suficiente tiempo para prepararse. Tomemos un ejemplo e intentemos comprender este párrafo:

Kotlin

// sample kotlin program
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.coroutines.*
 
class MainActivity : AppCompatActivity() {
   
    val TAG:String = "Main Activity"
   
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        val job = GlobalScope.launch(Dispatchers.Default) {
            Log.d(TAG,"Starting the long calculation...")
             
            // running the loop from 30 to 40
            for(i in 30..40)
            {
                Log.d(TAG, "Result for i =$i : ${fib(i)}")
            }
            Log.d(TAG, "Ending the long calculation...")
        }
 
        runBlocking {
            delay(2000)
            job.cancel()
            Log.d(TAG, "Main Thread is Running")
        }
    }
     
    // fibonacci function
    fun fib(n:Int):Long
    {
        return if(n==0) 0
        else if(n==1) 1
        else fib(n-1) + fib(n-2)
    }
}

La salida del registro es la siguiente:

Las marcas de tiempo se muestran mediante un círculo ovalado

Log Output

Se puede ver que incluso después de que se haya encontrado el método cancel() , nuestra corrutina continuará calculando el resultado de Fibonacci de los números. Es así porque nuestra rutina estaba tan ocupada haciendo el cálculo que no tiene tiempo para cancelarse. Suspender allí no tiene una función suspendida (como delay() ), no tenemos suficiente tiempo para decirle a la corrutina que ha sido cancelada. Así que tenemos que comprobar manualmente si la rutina se ha cancelado o no. Esto se puede hacer usando isActive para verificar si la rutina está activa o no. 

Kotlin

// sample kotlin program
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.coroutines.*
 
class MainActivity : AppCompatActivity() {
   
    val TAG:String = "Main Activity"
   
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        val job = GlobalScope.launch(Dispatchers.Default) {
            Log.d(TAG, "Starting the long calculation...")
            for(i in 30..40)
            {
                  // using isActive functionality to check whether the
                  // coroutine is active or not
                if(isActive)
                Log.d(TAG, "Result for i =$i : ${fib(i)}")
            }
            Log.d(TAG, "Ending the long calculation...")
        }
 
        runBlocking {
            delay(2000)
            job.cancel()
            Log.d(TAG, "Main Thread is Running")
        }
    }
 
    fun fib(n:Int):Long
    {
        return if(n==0) 0
        else if(n==1) 1
        else fib(n-1) + fib(n-2)
    }
}

La salida del registro es la siguiente:

Las marcas de tiempo se muestran mediante un círculo ovalado

Log Output

Se puede ver que el uso de isActive ha aumentado la conciencia de corrutina hacia su cancelación y realiza mucho menos cálculo después de ser cancelado, en comparación con cuando no se ha utilizado isActive.

conTiempoFuera() 

La rutina de Kotlin ha encontrado una buena solución a los problemas anteriores, es decir, la rutina se cancelará automáticamente y no hará más cálculos cuando haya transcurrido un cierto tiempo y withTimeOut() ayuda a hacerlo. No hay necesidad de cancelar la rutina manualmente usando la función runBlocking() . Veamos cómo funciona la función withTimeOut() :

Kotlin

// sample kotlin program
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.coroutines.*
 
class MainActivity : AppCompatActivity() {
   
    val TAG:String = "Main Activity"
   
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        val job = GlobalScope.launch(Dispatchers.Default) {
            Log.d(TAG, "Starting the long calculation...")
             
            // using withTimeOut function
            // which runs the coroutine for 3sec
            withTimeout(3000L)
            {
                for(i in 30..40)
                {
                    if(isActive)
                        Log.d(TAG, "Result for i =$i : ${fib(i)}")
                }
            }
            Log.d(TAG, "Ending the long calculation...")
        }
 
    }
 
    fun fib(n:Int):Long
    {
        return if(n==0) 0
        else if(n==1) 1
        else fib(n-1) + fib(n-2)
    }
}

La salida del registro es la siguiente:

Las marcas de tiempo se muestran mediante un círculo ovalado

Log Output

Publicación traducida automáticamente

Artículo escrito por lavishgarg26 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *