← Kotlin EspañolChapter 11 of 13

Corrutinas

## Objetivos de Aprendizaje - Comprender las corrutinas y sus beneficios - Usar funciones suspend - Lanzar corrutinas con launch y async - Trabajar con constructores de corrutinas - Gestionar alcances y despachadores de corrutinas ## ¿Qué son las Corrutinas? Las corrutinas son la solución de Kotlin para programación asíncrona. Son hilos ligeros que pueden ser suspendidos y reanudados. ### vs Hilos - Los hilos son pesados, las corrutinas son ligeras - Millones de corrutinas pueden ejecutarse en pocos hilos - Las corrutinas pueden ser suspendidas sin bloquear ```kotlin import kotlinx.coroutines.* fun main() { println("Starting...") // Launch a coroutine GlobalScope.launch { delay(1000) // Non-blocking delay println("Inside coroutine") } println("After launch...") Thread.sleep(2000) // Keep main thread alive println("Done") } ``` ## Funciones Suspend `suspend` marca una función que puede ser pausada y reanudada: ```kotlin import kotlinx.coroutines.* suspend fun fetchData(): String { delay(1000) // Suspends without blocking return "Data loaded" } fun main() = runBlocking { println("Before") val data = fetchData() println(data) println("After") } ``` ## Constructores de Corrutinas ### launch Fire and forget - no retorna resultado: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { delay(1000) println("Task completed") } println("Waiting...") job.join() // Wait for job to complete println("Done") } ``` ### async Retorna un resultado vía Deferred: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val deferred = async { delay(1000) "Result" } println("Waiting for result...") val result = deferred.await() println("Result: $result") } ``` ### runBlocking Bloquea el hilo actual hasta que las corrutinas completen: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { launch { delay(500) println("Task 1") } launch { delay(300) println("Task 2") } println("Waiting...") } ``` ## Concurrencia Estructurada ### coroutineScope Crea un alcance que espera a todos los hijos: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { coroutineScope { launch { delay(1000) println("Task 1") } launch { delay(500) println("Task 2") } } println("All tasks completed") } ``` ### launch en coroutineScope ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { doWork() } suspend fun doWork() = coroutineScope { launch { delay(200) println("Work 1") } launch { delay(100) println("Work 2") } println("Scope started") } ``` ## Despachadores Controlan qué hilo ejecuta la corrutina: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { launch { // Default dispatcher println("Default: ${Thread.currentThread().name}") } launch(Dispatchers.IO) { println("IO: ${Thread.currentThread().name}") } launch(Dispatchers.Default) { println("Default: ${Thread.currentThread().name}") } launch(Dispatchers.Unconfined) { println("Unconfined: ${Thread.currentThread().name}") } } ``` ### Con Contexto ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { launch(Dispatchers.Default) { println("Running in Default dispatcher") } withContext(Dispatchers.IO) { println("Running in IO dispatcher") } } ``` ## Manejo de Excepciones ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { try { repeat(1000) { i -> println("Working $i") delay(500) } } finally { println("Cleanup!") } } delay(2000) job.cancelAndJoin() println("Cancelled") } ``` ### withTimeout ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { try { withTimeout(1500) { repeat(1000) { i -> println("Working $i") delay(500) } } } catch (e: TimeoutCancellationException) { println("Timed out!") } } ``` ## Ejecución Secuencial Sin corrutinas: ```kotlin import kotlinx.coroutines.* import kotlinx.coroutines.experimental.* suspend fun doTask1(): String { delay(1000) return "Task 1" } suspend fun doTask2(): String { delay(1000) return "Task 2" } fun main() = runBlocking { val time = measureTimeMillis { val result1 = doTask1() val result2 = doTask2() println("$result1, $result2") } println("Took ${time}ms") // ~2000ms } ``` Con async: ```kotlin fun main() = runBlocking { val time = measureTimeMillis { val result1 = async { doTask1() } val result2 = async { doTask2() } println("${result1.await()}, ${result2.await()}") } println("Took ${time}ms") // ~1000ms } ``` ## Cancelación ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { repeat(1000) { i -> println("Working $i") delay(500) } } delay(2000) println("Cancelling...") job.cancel() job.join() println("Cancelled") } ``` ### Verificación isActive ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { val job = launch { var i = 0 while (isActive) { // Check if still active println("Working $i") delay(500) i++ } } delay(2000) job.cancelAndJoin() println("Done") } ``` ## Flows Los Flows son streams asíncronos fríos: ```kotlin import kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun main() = runBlocking { // Create a flow val flow = flow { for (i in 1..5) { delay(500) emit(i) } } // Collect flow flow.collect { value -> println("Received: $value") } } ``` ### Operadores de Flow ```kotlin import kotlinx.coroutines.* import kotlinx.coroutines.flow.* fun main() = runBlocking { (1..5).asFlow() .map { it * it } .filter { it > 5 } .collect { println(it) } } ``` ## Resumen - Las corrutinas son bloques asíncronos ligeros - `suspend` marca funciones que pueden ser pausadas - `launch` para fire-and-forget, `async` para resultados - `runBlocking` bloquea el hilo actual - `Dispatchers.IO`, `Dispatchers.Default`, `Dispatchers.Main` - Concurrencia estructurada con `coroutineScope` - `cancel()` y `withTimeout` para cancelación - Los Flows son streams asíncronos fríos

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →