async : ce que c’est, Deferred et comment fonctionnent les coroutines parallèles

Auteur : IT Sectr Publié le : 2026-06-22 Temps de lecture : 8 min

async — est un constructeur de coroutines en Kotlin qui lance une coroutine et retourne un objet Deferred<T> pour obtenir le résultat d’une opération asynchrone. async permet d’exécuter plusieurs tâches en parallèle et d’agréger leurs résultats via await(). Selon le guide JetBrains, 2024, async est la méthode préférée pour organiser les calculs parallèles dans les coroutines.

Points clés

  • async — un constructeur de coroutines retournant Deferred<T> avec le résultat d’une opération asynchrone
  • Deferred — une promesse asynchrone, héritant de Job, avec la méthode await() pour obtenir le résultat
  • async permet d’exécuter des tâches indépendantes en parallèle, réduisant le temps total
  • await() — une fonction suspend qui suspend la coroutine jusqu’à l’obtention du résultat sans bloquer
  • Concurrence structurée avec async garantit l’annulation de toutes les tâches parallèles en cas d’erreur

Qu’est-ce que async dans Kotlin Coroutines ?

async — est une fonction d’extension de CoroutineScope qui crée une coroutine retournant un résultat. Contrairement à launch, async retourne Deferred<T> — un objet représentant une valeur future. Une coroutine lancée via async s’exécute concurremment avec d’autres coroutines, permettant de paralléliser les calculs.

async est utilisé lorsque le résultat d’une opération asynchrone est nécessaire pour un traitement ultérieur : chargement de données depuis plusieurs sources, traitement par lots de collections, requêtes parallèles à diverses API. Deferred est créé immédiatement, et le résultat est disponible après l’achèvement de la coroutine.

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())
}

Syntaxe de async et Deferred

La signature de async est similaire à launch : les mêmes paramètres CoroutineContext, CoroutineStart et un bloc suspend. La différence réside dans le type de retour — Deferred<T> au lieu de Job, où T est le type de résultat retourné par la dernière expression du bloc.

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

Deferred<T> — une interface héritant de Job et ajoutant les méthodes await(), getCompleted(), getCompletionExceptionOrNull(). await() est une fonction suspend et ne peut être appelée qu’à l’intérieur d’une coroutine ou d’une autre fonction suspend. getCompleted() est une méthode non bloquante qui lève une exception si la coroutine n’est pas encore terminée.

Tâches parallèles avec async

Le principal avantage de async est la possibilité d’exécuter des tâches en parallèle. Au lieu d’attendre chaque opération séquentiellement (temps total = somme des temps), async lance les coroutines simultanément, réduisant le temps total à la durée de l’opération la plus longue.

Chargement parallèle de données

Un scénario typique — charger le profil de l’utilisateur, ses paramètres et son historique de commandes avec trois requêtes async parallèles. Après l’achèvement des trois, les résultats sont combinés en un seul modèle de données.

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 fonction coroutineScope lance des coroutines filles et attend leur achèvement avant de retourner le résultat. L’ensemble du bloc s’exécute en parallèle, pas séquentiellement.

Traitement des résultats Deferred

Deferred prend en charge plusieurs méthodes pour travailler avec le résultat. En plus de await(), il existe des méthodes pour vérifier l’état, obtenir une valeur terminée et agréger plusieurs Deferred via les fonctions utilitaires de Kotlin Coroutines.

MéthodeDescriptionSuspend ?
await()Suspend la coroutine jusqu’à l’obtention du résultatOui
getCompleted()Retourne le résultat si la coroutine est terminée (sinon Exception)Non
getCompletionExceptionOrNull()Retourne l’exception en cas d’erreur ou nullNon
isCompletedVérifie si la coroutine est terminéeNon

Pour agréger une liste de Deferred, on utilise awaitAll() — une fonction qui suspend l’exécution jusqu’à ce que tous les Deferred de la collection soient terminés. Si au moins un s’est terminé avec une erreur, awaitAll() lève l’exception.

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

Différences entre async et launch

Le choix entre async et launch dépend de la nécessité du résultat de la coroutine. launch retourne Job et convient aux opérations fire-and-forget, async retourne Deferred et est utilisé pour les tâches qui retournent des données. En termes de syntaxe et de paramètres, les constructeurs sont identiques.

  • launch → Job (pas de résultat), async → Deferred<T> (résultat T)
  • launch — tâches fire-and-forget (journalisation, mise en cache, envoi d’analyses)
  • async — calculs parallèles (chargement depuis plusieurs API, traitement par lots)
  • Les deux prennent en charge la concurrence structurée et les paramètres CoroutineStart
  • await() est disponible uniquement pour Deferred, launch ne fournit pas de résultat

Règle importante : n’utilisez jamais async pour du fire-and-forget. Si le résultat de la coroutine n’est pas nécessaire, utilisez launch. async crée une surcharge en créant Deferred, ce qui n’est pas justifié dans de tels scénarios.

Exemples de async en développement mobile

Dans Android, async est utilisé pour les opérations parallèles au sein de ViewModel et UseCases. Scénarios typiques : charger le profil et le fil d’actualité simultanément, obtenir la météo depuis plusieurs services météorologiques, synchronisation par lots des données avec le serveur.

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 }
        }
    }
}

Il est recommandé d’encapsuler un groupe de async dans coroutineScope ou supervisorScope pour isoler les erreurs. supervisorScope permet aux autres coroutines async de continuer même si l’une échoue — utile pour les opérations non critiques.

Foire aux questions

Peut-on utiliser async sans await ?

On peut, mais c’est inutile. async sans await() lance une coroutine mais son résultat est perdu. Si le résultat n’est pas nécessaire, utilisez launch — il ne crée pas Deferred et est plus efficace en mémoire et en performances.

Comment async gère-t-il les exceptions ?

Une exception dans async est stockée dans Deferred. L’appel à await() lève cette exception. Pour vérifier sans lever, utilisez getCompletionExceptionOrNull(). Lors de l’utilisation de coroutineScope, une erreur annule toutes les coroutines filles.

Qu’est-ce que awaitAll dans Kotlin Coroutines ?

awaitAll() — une fonction d’extension pour Iterable<Deferred<T>> qui suspend la coroutine jusqu’à ce que tous les Deferred soient terminés. Retourne une liste de résultats. Si au moins un Deferred échoue, elle lève l’exception et annule les autres.

En quoi async diffère-t-il de GlobalScope.async ?

Oui. async est une fonction d’extension de CoroutineScope liée à la portée. GlobalScope.async crée une coroutine sans liaison au cycle de vie — elle peut s’exécuter indéfiniment. GlobalScope n’est pas recommandé dans Android en raison du risque de fuites.

Combien de coroutines async peut-on lancer pour des requêtes parallèles ?

Le nombre est dicté par le dispatcher : Dispatchers.IO supporte jusqu’à 64 threads simultanés, Dispatchers.Default — jusqu’au nombre de cœurs CPU. Pour les opérations massives, utilisez un parallélisme limité via Semaphore ou mapNotNull avec awaitAll.

Résumé

  • async — un constructeur de coroutines retournant Deferred<T> pour l’obtention asynchrone de résultats
  • Deferred hérite de Job et ajoute les méthodes await(), getCompleted(), getCompletionExceptionOrNull()
  • Exécution parallèle avec async réduit le temps total à la durée de l’opération la plus longue
  • awaitAll() — un utilitaire pour attendre tous les Deferred d’une collection
  • coroutineScope — enveloppe recommandée pour un groupe de async avec garantie d’annulation
  • N’utilisez pas async pour du fire-and-forget — utilisez launch à la place
  • Dans Android, async est utilisé pour le chargement parallèle dans ViewModel avec viewModelScope

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi