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 →