Las corrutinas (Coroutines) son hilos ligeros de Kotlin para programación asíncrona, disponibles a través de la librería kotlinx.coroutines. Según JetBrains Kotlin Documentation, 2026, Coroutines permiten suspender la ejecución de una función sin bloquear un hilo, a diferencia de los Thread tradicionales. Las corrutinas se ejecutan en un pool de hilos limitado, lo que las hace mil veces más ligeras que los hilos nativos. Kotlin Coroutines están completamente integradas con Android Jetpack, Retrofit, Room y otras bibliotecas populares del ecosistema Android.
Puntos Clave
Coroutines son un mecanismo de programación asíncrona en Kotlin, implementado en la librería kotlinx.coroutines. A diferencia de los hilos del sistema operativo, las corrutinas no están vinculadas a un hilo específico: pueden suspenderse en un hilo y reanudarse en otro. Un solo hilo puede ejecutar miles de corrutinas, alternando entre ellas con una sobrecarga mínima.
Las corrutinas aparecieron en Kotlin 1.3 (2018) como una función experimental y se volvieron estables en Kotlin 1.5 (2021). Coroutines resuelven el problema de callback hell de manera similar a async/await, pero proporcionan una API más rica: canales (Channel), Flow, manejo de excepciones en la jerarquía Job e integración directa con Android Lifecycle.
Según JetBrains (2025), cada corrutina consume alrededor de 100 bytes de memoria frente a 1+ MB de un hilo nativo. Esto permite ejecutar millones de corrutinas en una sola aplicación sin riesgo de OutOfMemoryError. Es precisamente la ligereza de las corrutinas lo que las convierte en la herramienta preferida para la asincronía en Android.
Cada corrutina Kotlin se compila en una máquina de estados mediante Continuation Passing Style (CPS). El compilador añade un parámetro Continuation oculto a cada función suspend. Continuation contiene el punto de reanudación y todas las variables locales. Cuando una corrutina se suspende, el runtime guarda Continuation, y cuando se reanuda, lo restaura en cualquier hilo disponible del pool de Dispatcher.
suspend es una palabra clave de Kotlin que marca una función como suspendible. Esta función solo se puede llamar desde otra función suspend o desde una corrutina. Dentro de una función suspend, se pueden llamar a otras funciones suspend en cualquier orden, y cada punto de llamada es un punto potencial de suspensión.
La mecánica es simple: cuando una función suspend llama a otra función suspend, se suspende en ese punto, liberando el hilo. Una vez que la función llamada se completa, el runtime continúa la ejecución desde el lugar guardado. Esto se denomina cooperative cancellation: ningún hilo se bloquea.
Importante: una función suspend no es asíncrona por defecto. El orden de ejecución sigue siendo secuencial si no se utilizan launch o async. suspend solo permite que la función se pause sin bloquear el hilo y forme parte del contexto de corrutina. Continuation Passing Style es un modelo de compilación donde cada función suspend recibe un callback Continuation oculto, y el compilador genera una máquina de estados para gestionar las suspensiones y reanudaciones.
CoroutineScope es un contexto que define el ciclo de vida de las corrutinas. Todas las corrutinas deben lanzarse dentro de un scope. Cuando un scope se cancela (por ejemplo, cuando finaliza una Activity), todas sus corrutinas hijas se cancelan automáticamente. Esto evita fugas de tareas en segundo plano. Android Jetpack proporciona scopes predefinidos para cada componente: viewModelScope para ViewModel y lifecycleScope para Activity y Fragment, que se cancelan automáticamente al destruirse el componente correspondiente.
Structured Concurrency es un principio que garantiza que una corrutina no finalice hasta que todas sus corrutinas hijas hayan finalizado. La jerarquía Job forma un árbol: una corrutina raíz crea un parent job, los hijos crean child jobs. La cancelación de un parent job se propaga a todos los hijos. Structured Concurrency es una diferencia fundamental entre corrutinas y hilos.
| Scope | Dónde se usa | Cancelación |
|---|---|---|
| GlobalScope | Solo para tareas daemon | No se cancela automáticamente |
| viewModelScope | Android ViewModel | Al limpiar el ViewModel |
| lifecycleScope | Android Activity/Fragment | Al destruirse el lifecycle |
| coroutineScope | Dentro de función suspend | Al cancelar la job padre |
Un Job normal cancela todos los siblings cuando una corrutina hija falla. SupervisorJob es una excepción: un fallo en una corrutina hija no afecta a las demás. Esto es importante cuando varias tareas independientes se ejecutan en paralelo y una de ellas puede fallar sin necesidad de cancelar las otras.
Dispatchers determinan en qué hilos se ejecutan las corrutinas. Dispatchers.Main — el hilo principal de UI de Android. Dispatchers.IO — un pool para operaciones bloqueantes (red, disco). Dispatchers.Default — para tareas intensivas en CPU. Dispatchers.Unconfined — comienza en el hilo actual pero no garantiza permanecer en él. Elegir el Dispatcher correcto es crítico para el rendimiento: una tarea IO en Default bloqueará el pool de cómputo, mientras que una tarea de CPU en IO creará hilos innecesarios.
withContext — una función para cambiar de Dispatcher dentro de una corrutina. Por ejemplo, una función suspend que analiza JSON puede cambiar a Dispatchers.Default para el cómputo y volver a Dispatchers.Main para actualizar la UI. withContext es el constructor más utilizado en el desarrollo Android.
launch — lanza una corrutina, devuelve un Job, no devuelve un resultado (fire-and-forget). async — lanza una corrutina, devuelve un Deferred del que se puede obtener el resultado mediante await. runBlocking — bloquea el hilo actual para ejecutar una corrutina (solo para pruebas y funciones main). Elección del constructor depende del escenario: launch es adecuado para eventos y actualizaciones, async para tareas con resultado, runBlocking solo para pruebas o puntos de entrada.
Consideremos tres escenarios prácticos: una corrutina básica con launch, una llamada paralela con async y el manejo de errores con SupervisorJob.
viewModelScope.launch lanza una corrutina en el contexto del ViewModel. Cuando el ViewModel se limpia, la corrutina se cancela automáticamente.
class ProfileViewModel : ViewModel() {
fun loadUser() {
viewModelScope.launch(Dispatchers.IO) {
val user = api.fetchUser()
withContext(Dispatchers.Main) {
showUser(user)
}
}
}
}
coroutineScope con async lanza tres peticiones en paralelo. Los resultados se recogen mediante .await(). Si alguna petición falla, todas se cancelan.
suspend fun loadDashboard(): Dashboard = coroutineScope {
val user = async { api.fetchUser() }
val posts = async { api.fetchPosts() }
val stats = async { api.fetchStats() }
Dashboard(user.await(), posts.await(), stats.await())
}
SupervisorJob permite que cada corrutina finalice de forma independiente. Un error en una petición no cancela las demás.
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
try { api.fetchUsers() } catch (e: Exception) { log(e) }
}
scope.launch {
try { api.fetchPosts() } catch (e: Exception) { log(e) }
}
Hilos (Thread) son un primitivo del sistema operativo. Cada hilo tiene su propia pila (~1 MB) y requiere una llamada al sistema para crearse y cambiarse. Corrutinas son un primitivo del lenguaje, no vinculado al SO. Utilizan Continuation para guardar el estado y cambian a nivel de runtime sin llamadas al sistema.
Según Google (2025), usar corrutinas en lugar de hilos reduce el consumo de memoria para tareas en segundo plano en aplicaciones Android en un 90–95%. Todas las bibliotecas modernas de Android (Retrofit, Room, WorkManager) tienen soporte integrado para corrutinas mediante funciones suspend. Ktor (framework cliente HTTP de JetBrains) también está construido completamente sobre corrutinas, proporcionando funciones suspend para cada petición sin API de callbacks. Room admite corrutinas mediante funciones suspend en DAO, lo que permite ejecutar consultas a la BD sin bloquear el hilo principal.
Los hilos siguen siendo necesarios para código nativo a través de JNI, llamadas bloqueantes de CPU-intensive sin límite de tiempo (renderizado de vídeo, simulaciones) y al integrarse con bibliotecas C. Para todo lo demás — corrutinas.
Preguntas Frecuentes
Corrutina es una unidad de trabajo suspendible que se ejecuta en un hilo existente. Un hilo es un recurso del sistema con su propia pila. Las corrutinas son miles de veces más ligeras que los hilos y no bloquean recursos al suspenderse.
Dispatchers.IO está diseñado para operaciones de E/S bloqueantes (red, archivos) y puede crear nuevos hilos cuando sea necesario. Dispatchers.Default tiene un pool de tamaño fijo (número de núcleos de CPU) para cómputos intensivos en CPU.
Job.cancel() cancela la corrutina y todos sus hijos. Para comprobar la cancelación dentro de una corrutina, use ensureActive() — lanza una CancellationException si la corrutina está cancelada.
Sí — a través de la librería kotlinx-coroutines-rx3. Proporciona funciones awaitSingle, awaitFirst y otras para convertir Observable/Single en funciones suspend y viceversa mediante flowable.
Flow es un flujo de datos asíncrono en frío, el equivalente en corrutinas de RxJava Observable. Flow emite valores secuencialmente y finaliza con una excepción o éxito. Soporta map, filter, catch y otros operadores.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también