Introducción a la programación asíncrona en Kotlin
Las aplicaciones modernas requieren alto rendimiento y capacidad de respuesta. La programación asíncrona permite ejecutar operaciones largas (solicitudes de red, lectura de archivos, trabajo con bases de datos) sin bloquear el hilo principal de ejecución. En Kotlin, para esto se utiliza un mecanismo potente y elegante: las corrutinas (coroutines).
A diferencia de los hilos tradicionales (threads), las corrutinas son ligeras, se gestionan a nivel del lenguaje y no requieren enormes recursos del sistema. Esto las convierte en una herramienta ideal para escribir código asíncrono que sea fácil de leer y mantener. En esta guía, analizaremos los conceptos básicos de la programación asíncrona en Kotlin desde cero.
1. Fundamentos de las corrutinas: ¿qué son y cómo funcionan?
Una corrutina es una instancia de una operación computacional suspendible (suspendable). Puede suspenderse en un punto del código y reanudarse en otro, sin bloquear el hilo. Para trabajar con corrutinas, es necesario agregar la librería kotlinx.coroutines.
Agregar la dependencia
Añada al archivo build.gradle.kts:
dependencies { implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")}Primera corrutina
Para iniciar una corrutina se utiliza el constructor launch. Este inicia una nueva corrutina en segundo plano.
import kotlinx.coroutines.*
fun main() = runBlocking { // runBlocking bloquea el hilo principal para esperar las corrutinas println("Inicio: ${Thread.currentThread().name}")
launch { // inicio de una nueva corrutina delay(1000L) // suspendemos por 1 segundo (¡no bloquea el hilo!) println("Corrutina: ${Thread.currentThread().name}") }
println("Fin: ${Thread.currentThread().name}")}Salida:
Inicio: mainFin: mainCorrutina: mainObserve: delay es una función suspend que suspende la corrutina, pero no bloquea el hilo. Mientras la corrutina "duerme", el hilo puede ejecutar otro código.
2. Funciones suspend: los bloques de construcción de la asincronía
Una función suspend es una función que puede ser suspendida y reanudada más tarde. Estas funciones solo pueden ser llamadas desde otras funciones suspend o desde una corrutina. Se marcan con la palabra clave suspend.
Ejemplo de función suspend
import kotlinx.coroutines.*
suspend fun fetchData(): String { delay(2000L) // simulación de una solicitud de red larga return "Datos recibidos"}
fun main() = runBlocking { println("Solicitando datos...") val result = fetchData() // llamada a función suspend desde una corrutina println(result)}Ejecución paralela con async/await
Si necesita ejecutar varias tareas en paralelo, use el constructor async. Este devuelve un Deferred — un objeto que almacena el resultado futuro. Puede obtener el resultado con await().
import kotlinx.coroutines.*
suspend fun loadUser(): String { delay(1000L) return "Usuario: Iván"}
suspend fun loadPosts(): String { delay(1500L) return "Publicaciones: Noticias, Artículos"}
fun main() = runBlocking { val time = measureTimeMillis { val userDeferred = async { loadUser() } val postsDeferred = async { loadPosts() }
println(userDeferred.await()) println(postsDeferred.await()) } println("Tiempo total: $time ms") // ~1500 ms (tiempo máximo de los dos)}Sin async, las tareas se ejecutarían secuencialmente y tomarían ~2500 ms. La ejecución paralela redujo el tiempo a ~1500 ms.
3. Dispatchers: gestión de hilos
Un Dispatcher determina en qué hilo o grupo de hilos se ejecutará la corrutina. Los dispatchers más comunes son: