Je lisais Bases de Coroutine essayant de comprendre et d'apprendre.
Il y a une partie avec ce code:
fun main() = runBlocking { // this: CoroutineScope
launch {
delay(200L)
println("Task from runBlocking")
}
coroutineScope { // Creates a new coroutine scope
launch {
delay(900L)
println("Task from nested launch")
}
delay(100L)
println("Task from coroutine scope") // This line will be printed before nested launch
}
println("Coroutine scope is over") // This line is not printed until nested launch completes
}
La sortie se passe comme suit:
Task from coroutine scope
Task from runBlocking
Task from nested launch
Coroutine scope is over
Ma question est pourquoi cette ligne:
println("Coroutine scope is over") // This line is not printed until nested launch completes
s'appelle toujours dernier?
Ne devrait-il pas être appelé depuis le:
coroutineScope { // Creates a new coroutine scope
....
}
est suspendue?
Il y a aussi une note ici:
La principale différence entre runBlocking et coroutineScope est que ce dernier ne bloque pas le thread en cours en attendant que tous les enfants soient terminés.
Je ne comprends pas en quoi coroutineScope et runBlocking sont différents ici? coroutineScope ressemble à son blocage car il n’atteint que la dernière ligne à la fin.
Quelqu'un peut-il m'éclairer ici?
Merci d'avance.
Je ne comprends pas en quoi coroutineScope et runBlocking sont différents ici? coroutineScope ressemble à son blocage car il n’atteint que la dernière ligne à la fin.
Du point de vue du code dans le bloc, votre compréhension est correcte. La différence entre runBlocking
et coroutineScope
se produit à un niveau inférieur: qu'arrive-t-il au thread lorsque la coroutine est bloquée?
runBlocking
n'est pas un suspend fun
. Le fil qui l'a appelé reste à l'intérieur jusqu'à la fin de la coroutine.
coroutineScope
est un suspend fun
. Si votre coroutine est suspendue, la fonction coroutineScope
est également suspendue. Cela permet à la fonction de niveau supérieur, une fonction sans suspension qui a créé le coroutine, de continuer à s'exécuter sur le même thread. Le thread a "échappé" au bloc coroutineScope
et est prêt à effectuer d'autres tâches.
Dans votre exemple spécifique: lorsque coroutineScope
est suspendu, le contrôle retourne au code d'implémentation à l'intérieur de runBlocking
. Ce code est une boucle d'événement qui gère toutes les lignes que vous avez commencées. Dans votre cas, il y aura des routines programmées pour s'exécuter après un délai. Lorsque le moment sera venu, il reprendra la coroutine appropriée, qui durera quelques instants, sera suspendue puis le contrôle sera à nouveau à l'intérieur de runBlocking
.
Bien que ce qui précède décrit les similitudes conceptuelles, il devrait également vous montrer que runBlocking
est un outil complètement différent de coroutineScope
.
runBlocking
est une construction de bas niveau, à utiliser uniquement dans du code d'infrastructure ou dans des exemples autonomes comme le vôtre. Il transforme un thread existant en boucle d'événement et crée sa coroutine avec un Dispatcher
qui publie des coroutines de reprise dans la file d'attente de la boucle d'événement.
coroutineScope
est une construction orientée utilisateur, utilisée pour délimiter les limites d'une tâche en cours de décomposition parallèle. Vous l'utilisez pour attendre commodément tout le travail async
qui s'y déroule, obtenir le résultat final et gérer toutes les pannes en un point central.
runBlocking
just bloque le thread actuel jusqu'à ce que les coroutines internes soient terminés. Ici, le thread qui exécute runBlocking
sera bloqué jusqu'a la coroutine de coroutineScope
sera terminée.
Tout d'abord, launch
n'autorisera pas le thread à exécuter les instructions venant après runBlocking
, mais autorisera les instructions immédiatement après ce bloc launch
- c'est pourquoi Task from coroutine scope
est imprimé avant que Task from runBlocking
.
Mais imbriqué coroutineScope
dans le contexte de runBlocking
n'autorisera pas le thread à exécuter les instructions qui viendront après ce bloc coroutineScope
, car runBlocking
bloquera le thread. jusqu'à ce que la coroutine de coroutineScope
soit complètement terminée. Et c'est pourquoi Coroutine scope is over
viendra toujours après Task from nested launch
.
De cet article merveilleux https://jivimberg.io/blog/2018/05/04/parallel-map-in-kotlin/
suspend fun <A, B> Iterable<A>.pmap(f: suspend (A) -> B): List<B> = coroutineScope {
map { async { f(it) } }.awaitAll()
}
Avec runBlocking, nous n’utilisions pas la concurrence simultanée structurée. Par conséquent, l’invocation de f pouvait échouer et toutes les autres exécutions se poursuivaient sans faille. Et aussi nous ne jouions pas à Nice avec le reste du code. En utilisant runBlocking, nous avons bloqué le thread de manière forcée jusqu'à la fin de l'exécution de pmap, au lieu de laisser l'appelant décider du déroulement de l'exécution.