Concurrencia y multiproceso en Kotlin: corrutinas, hilos y ejemplos prácticos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Concurrencia y multihilo en Kotlin: de la teoría a la práctica

Las aplicaciones modernas requieren un funcionamiento rápido y receptivo. Ya sea la carga de datos desde la red, el procesamiento de grandes conjuntos de datos o el trabajo con la interfaz de usuario, no se puede prescindir de la concurrencia y el multihilo. Kotlin, como lenguaje moderno para JVM, Android y proyectos multiplataforma, ofrece herramientas flexibles para resolver estas tareas. En este artículo, analizaremos los enfoques clave: desde los hilos clásicos hasta las corrutinas ligeras, y mostraremos cómo escribir código eficiente.



1. Hilos (Threads) en Kotlin: el enfoque clásico

Los hilos son el mecanismo básico de ejecución paralela, heredado de Java. En Kotlin, puedes crear hilos igual que en Java, pero con una sintaxis más concisa.

Ejemplo simple de inicio de un hilo:

fun main() {    thread {        println("Hilo iniciado: ${Thread.currentThread().name}")        Thread.sleep(1000)        println("Hilo finalizado")    }    println("Hilo principal: ${Thread.currentThread().name}")    Thread.sleep(2000)}

Sin embargo, los hilos tienen desventajas: son pesados (cada hilo consume alrededor de 1 MB de memoria), su cantidad es limitada y el cambio de contexto es costoso. Para aplicaciones modernas con miles de tareas paralelas, los hilos no son la mejor opción. Aquí es donde las corrutinas vienen al rescate.



2. Corrutinas (Coroutines): una alternativa ligera

Las corrutinas son la característica principal de Kotlin para la concurrencia. Funcionan sobre los hilos, pero utilizan menos recursos. Un solo hilo puede ejecutar miles de corrutinas, suspendiéndolas y reanudándolas sin bloqueo.

Para empezar, añade la dependencia en build.gradle.kts:

dependencies {    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")}

Ejemplo de una corrutina simple:

import kotlinx.coroutines.*

fun main() = runBlocking { launch { delay(1000L) // retardo no bloqueante println("¡Mundo desde la corrutina!") } println("Hola desde la corrutina principal") delay(2000L)}

Aquí, launch inicia una nueva corrutina, y delay la suspende sin bloquear el hilo. runBlocking se utiliza para bloquear el hilo principal hasta que todas las corrutinas finalicen (normalmente se usa solo en main y pruebas).



2.1. Funciones suspend

La palabra clave suspend permite suspender la ejecución de una función sin bloquear el hilo. Esta es la base de la programación asíncrona en Kotlin.

suspend fun fetchUser(): String {    delay(500L) // simulación de una solicitud de red    return "User123"}

fun main() = runBlocking { val user = fetchUser() println("Usuario obtenido: $user")}


2.2. Async y Deferred para tareas paralelas

Si necesitas ejecutar varias tareas en paralelo y esperar sus resultados, usa async y Deferred:

fun main() = runBlocking {    val time = measureTimeMillis {        val user = async { fetchUser() }        val profile = async { fetchProfile() }        println("Resultados: ${user.await()}, ${profile.await()}")    }    println("Tiempo de ejecución: $time ms")}

suspend fun fetchUser(): String { delay(500) return "User"}

suspend fun fetchProfile(): String { delay(500) return "Profile"}

Ambas tareas se ejecutan en paralelo, lo que reduce el tiempo total.



3. Dispachadores de corrutinas (Dispatchers)

Los dispachadores determinan en qué hilos se ejecutarán las corrutinas. Tipos principales:

  • Dispatchers.Default — para tareas intensivas en CPU (por defecto).
  • Dispatchers.IO — para operaciones de entrada/salida (red, archivos).
  • Dispatchers.Main — para el hilo de UI (Android, JavaFX).

Blogs

Book Recommendations