async: qué es, Deferred y cómo funcionan las corrutinas paralelas

Autor: IT Sectr Publicado: 2026-06-22 Tiempo de lectura: 8 min

async — es un constructor de corrutinas en Kotlin que lanza una corrutina y devuelve un objeto Deferred<T> para obtener el resultado de una operación asíncrona. async permite ejecutar múltiples tareas en paralelo y agregar sus resultados mediante await(). Según la guía de JetBrains, 2024, async es la forma preferida de organizar cálculos paralelos en corrutinas.

Puntos Clave

  • async — un constructor de corrutinas que devuelve Deferred<T> con el resultado de una operación asíncrona
  • Deferred — una promesa asíncrona, heredera de Job, con el método await() para obtener el resultado
  • async permite ejecutar tareas independientes en paralelo, reduciendo el tiempo total
  • await() — una función suspend que suspende la corrutina hasta obtener el resultado sin bloquear
  • Concurrencia estructurada con async garantiza la cancelación de todas las tareas paralelas en caso de error

¿Qué es async en Kotlin Coroutines?

async — es una función de extensión de CoroutineScope que crea una corrutina devolviendo un resultado. A diferencia de launch, async devuelve Deferred<T> — un objeto que representa un valor futuro. Una corrutina lanzada mediante async se ejecuta concurrentemente con otras corrutinas, permitiendo paralelizar cálculos.

async se usa cuando el resultado de una operación asíncrona es necesario para su posterior procesamiento: carga de datos de múltiples fuentes, procesamiento por lotes de colecciones, solicitudes paralelas a varias API. Deferred se crea inmediatamente y el resultado está disponible después de que la corrutina se complete.

kotlin
import kotlinx.coroutines.*

suspend fun String.delayedValue(): String {
    delay(1000L)
    return this
}

fun main() = runBlocking {
    val deferred: Deferred<String> = async { "Hello".delayedValue() }
    println(deferred.await())
}

Sintaxis de async y Deferred

La firma de async es similar a launch: los mismos parámetros CoroutineContext, CoroutineStart y un bloque suspend. La diferencia está en el tipo de retorno — Deferred<T> en lugar de Job, donde T es el tipo de resultado devuelto por la última expresión del bloque.

kotlin
public fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T>

Deferred<T> — una interfaz que hereda Job y agrega los métodos await(), getCompleted(), getCompletionExceptionOrNull(). await() es una función suspend y solo puede llamarse dentro de una corrutina u otra función suspend. getCompleted() es un método no bloqueante que lanza una excepción si la corrutina aún no se ha completado.

Tareas paralelas con async

La principal ventaja de async es la capacidad de ejecutar tareas en paralelo. En lugar de esperar cada operación secuencialmente (tiempo total = suma de tiempos), async lanza corrutinas simultáneamente, reduciendo el tiempo total a la duración de la operación más larga.

Carga paralela de datos

Un escenario típico — cargar el perfil del usuario, sus ajustes y el historial de pedidos con tres solicitudes async paralelas. Después de que las tres se completen, los resultados se combinan en un único modelo de datos.

kotlin
suspend fun loadUserDashboard(userId: String): Dashboard = coroutineScope {
    val profile = async { api.getProfile(userId) }
    val settings = async { api.getSettings(userId) }
    val orders = async { api.getRecentOrders(userId) }

    Dashboard(
        profile = profile.await(),
        settings = settings.await(),
        orders = orders.await()
    )
}

La función coroutineScope lanza corrutinas hijas y espera su finalización antes de devolver el resultado. Todo el bloque se ejecuta en paralelo, no secuencialmente.

Manejo de resultados Deferred

Deferred admite varios métodos para trabajar con el resultado. Además de await(), hay métodos para verificar el estado, obtener un valor completado y agregar varios Deferred mediante las funciones de utilidad de Kotlin Coroutines.

MétodoDescripción¿Suspend?
await()Suspende la corrutina hasta obtener el resultado
getCompleted()Devuelve el resultado si la corrutina se completó (si no, Exception)No
getCompletionExceptionOrNull()Devuelve la excepción en caso de error o nullNo
isCompletedComprueba si la corrutina se ha completadoNo

Para agregar una lista de Deferred, se usa awaitAll() — una función que suspende la ejecución hasta que todos los Deferred de la colección se completen. Si al menos uno se completó con error, awaitAll() lanza la excepción.

kotlin
suspend fun <T> loadAll(requests: List<suspend () -> T>): List<T> {
    return coroutineScope {
        val deferreds = requests.map { async { it() } }
        deferreds.awaitAll()
    }
}

Diferencias entre async y launch

La elección entre async y launch depende de si se necesita el resultado de la corrutina. launch devuelve Job y es adecuado para operaciones de fire-and-forget, async devuelve Deferred y se usa para tareas que devuelven datos. En cuanto a sintaxis y parámetros, los constructores son idénticos.

  • launch → Job (sin resultado), async → Deferred<T> (resultado T)
  • launch — tareas fire-and-forget (registro, almacenamiento en caché, envío de analíticas)
  • async — cálculos paralelos (carga desde varias API, procesamiento por lotes)
  • Ambos admiten concurrencia estructurada y parámetros CoroutineStart
  • await() solo está disponible para Deferred, launch no proporciona resultado

Regla importante: nunca uses async para fire-and-forget. Si no se necesita el resultado de la corrutina, usa launch. async crea una sobrecarga por crear Deferred, lo que no está justificado en tales escenarios.

Ejemplos de async en desarrollo móvil

En Android, async se usa para operaciones paralelas dentro de ViewModel y UseCases. Escenarios típicos: cargar perfil y feed de noticias simultáneamente, obtener el clima de varios servicios meteorológicos, sincronización por lotes de datos con el servidor.

kotlin
class HomeViewModel : ViewModel() {
    fun loadHomeScreen() {
        viewModelScope.launch {
            val userData = async(Dispatchers.IO) { repository.getUserData() }
            val newsFeed = async(Dispatchers.IO) { repository.getNewsFeed() }
            val notifications = async(Dispatchers.IO) { repository.getNotifications() }

            val state = HomeState(
                user = userData.await(),
                news = newsFeed.await(),
                unread = notifications.await()
            )
            _uiState.update { state }
        }
    }
}

Se recomienda envolver un grupo de async en coroutineScope o supervisorScope para aislar errores. supervisorScope permite que las demás corrutinas async continúen incluso si una falla — útil para operaciones no críticas.

Preguntas Frecuentes

¿Se puede usar async sin await?

Se puede, pero no tiene sentido. async sin await() lanza una corrutina pero su resultado se pierde. Si no se necesita el resultado, usa launch — no crea un Deferred y es más eficiente en memoria y rendimiento.

¿Cómo maneja async las excepciones?

Una excepción dentro de async se almacena en Deferred. Llamar a await() lanza esta excepción. Para comprobar sin lanzar, usa getCompletionExceptionOrNull(). Al usar coroutineScope, un error cancela todas las corrutinas hijas.

¿Qué es awaitAll en Kotlin Coroutines?

awaitAll() — una función de extensión para Iterable<Deferred<T>> que suspende la corrutina hasta que todos los Deferred se completen. Devuelve una lista de resultados. Si al menos un Deferred falla, lanza la excepción y cancela el resto.

¿En qué se diferencia async de GlobalScope.async?

Sí. async es una función de extensión de CoroutineScope vinculada al ámbito. GlobalScope.async crea una corrutina sin vinculación al ciclo de vida — puede ejecutarse indefinidamente. GlobalScope no se recomienda en Android debido al riesgo de fugas.

¿Cuántas corrutinas async se pueden lanzar para solicitudes paralelas?

El número lo dicta el despachador: Dispatchers.IO admite hasta 64 subprocesos simultáneos, Dispatchers.Default — hasta el número de núcleos de CPU. Para operaciones masivas, usa paralelismo limitado mediante Semaphore o mapNotNull con awaitAll.

Resumen

  • async — un constructor de corrutinas que devuelve Deferred<T> para la obtención asíncrona de resultados
  • Deferred hereda Job y agrega los métodos await(), getCompleted(), getCompletionExceptionOrNull()
  • Ejecución paralela con async reduce el tiempo total a la duración de la operación más larga
  • awaitAll() — una utilidad para esperar todos los Deferred en una colección
  • coroutineScope — envoltorio recomendado para un grupo de async con garantía de cancelación
  • No uses async para fire-and-forget — usa launch en su lugar
  • En Android, async se usa para carga paralela en ViewModel con viewModelScope

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.

Discutir el proyecto

Lea también