web-dev-qa-db-fra.com

Quelle est la différence entre launch / join et async / wait dans les coroutines Kotlin

Dans la bibliothèque kotlinx.coroutines, vous pouvez démarrer un nouveau répertoire en utilisant launch (avec join) ou async (avec await). Quelle est la différence entre eux?

107
Roman Elizarov
  • launch est utilisé pour tirer et oublier la routine . C'est comme commencer un nouveau fil. Si le code à l'intérieur de launch se termine avec une exception, il est traité comme une exception ncaught ​​dans un thread - généralement imprimé sur stderr dans les applications JVM dorsales et bloque les applications Android. join est utilisé pour attendre l'achèvement de la coroutine lancée et il ne propage pas son exception. Cependant, une coroutine bloquée enfant ​​annule également son parent avec l'exception correspondante.

  • async est utilisé pour démarrer un coroutine qui calcule un résultat . Le résultat est représenté par une instance de Deferred et vous devez utiliser await dessus. Une exception non interceptée dans le code async est stockée dans le Deferred résultant et n'est livrée nulle part ailleurs. Elle sera supprimée en mode silencieux sauf si elle est traitée. Vous NE DEVEZ PAS oublier la coroutine que vous avez commencée avec async .

164
Roman Elizarov

Je trouve ce guide https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md utile. Je vais citer les parties essentielles

???? coroutine

Les coroutines sont essentiellement des fils légers.

Ainsi, vous pouvez penser à la coroutine comme à quelque chose qui gère le fil de manière très efficace.

???? lance

fun main(args: Array<String>) {
    launch { // launch new coroutine in background and continue
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("World!") // print after delay
    }
    println("Hello,") // main thread continues while coroutine is delayed
    Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}

Donc, launch démarre un fil d’arrière-plan, fait quelque chose et renvoie immédiatement un jeton sous la forme Job. Vous pouvez appeler join sur ce Job pour bloquer jusqu'à ce que ce thread launch se termine

fun main(args: Array<String>) = runBlocking<Unit> {
    val job = launch { // launch new coroutine and keep a reference to its Job
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    job.join() // wait until child coroutine completes
}

???? asynchrone

Conceptuellement, async est comme un lancement. Il commence une coroutine séparée qui est un fil léger qui fonctionne en même temps que toutes les autres coroutines. La différence est que launch renvoie un travail et ne génère aucune valeur résultante, alors que async renvoie un différé - un avenir léger non bloquant qui représente une promesse de fournir un résultat plus tard.

Donc, async démarre un fil d’arrière-plan, fait quelque chose et renvoie immédiatement un jeton sous la forme Deferred.

fun main(args: Array<String>) = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async { doSomethingUsefulOne() }
        val two = async { doSomethingUsefulTwo() }
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}

Vous pouvez utiliser .await () sur une valeur différée pour obtenir son résultat éventuel, mais différé est également un travail, vous pouvez donc l'annuler si nécessaire.

Donc, Deferred est en fait un Job. Voir https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html

interface Deferred<out T> : Job (source)

???? async est impatient par défaut

Il existe une option de paresse à asynchroniser à l'aide d'un paramètre de démarrage facultatif avec une valeur de CoroutineStart.LAZY. Il ne commence la coroutine que lorsque le résultat est attendu par certains ou si une fonction de démarrage est appelée.

55
onmyway133