Semblable à comment développement d’applications mobiles multiplateformes La programmation grand public, techniquement, asynchrone ou non bloquante est une nouvelle réalité. Lorsque vous créez des applications côté serveur, de bureau ou mobiles, il est important de fournir une expertise d’associé en soins infirmiers qui ne soit pas uniquement fluide du point de vue de l’utilisateur, mais évolutive une fois nécessaire.
Kotlin résout cet inconvénient dans une approche extrêmement polyvalente en fournissant un support coroutine au niveau du langage et en reléguant la plupart des aspects pratiques aux bibliothèques.
En prime, les coroutines n’ouvrent pas seulement les portes de la programmation asynchrone, elles offrent également une multitude de possibilités différentes comme la concurrence et les acteurs.
Kotlin, en tant que langage, fournit uniquement des API de bas niveau dépouillées dans sa bibliothèque courante pour modifier des bibliothèques variées afin d’utiliser des coroutines. Contrairement à plusieurs langages différents avec des capacités similaires, async et look ne sont pas des mots-clés dans Kotlin et ne font même pas partie de sa bibliothèque courante. De plus, la pensée de Kotlin de suspendre les performances fournit une abstraction plus sûre et moins faillible pour les opérations asynchrones que les contrats à terme et les garanties.
kotlinx.coroutines pourrait être une bibliothèque de coroutines développée par JetBrains. Il contient une variété de primitives coroutines de haut niveau couvertes par ce guide, ainsi que le lancement, l’async, l’attente et plus encore.
Il s’agit d’une option de base orient de kotlinx.coroutines avec une série d’exemples, répartis dans des sujets complètement différents.
Afin d’utiliser les coroutines, suivez également les exemples de ce guide, vous souhaitez disposer d’une dépendance sur le module kotlinx-coroutines-core.
Votre première coroutine
Une coroutine est une instance de calcul suspendable. C’est conceptuellement comme un thread, dans le sens où il faut un bloc de code à exécuter qui fonctionne en même temps avec le reste du code. Cependant, une coroutine n’est garantie à aucun thread spécifique. il doit suspendre son exécution dans un thread et reprendre dans un autre.
Les coroutines sont considérées comme des fils légers. Cependant, il existe une variété de variantes vitales qui rendent leur utilisation réelle très différente des threads.
1 2 3 4 5 6 7 8 |
fun main() = runBlocking { // CoroutineScope launch { // lance une nouvelle coroutine et démarre delay(1000L) // délai non bloquant pendant 1 seconde (par défaut le temps est ms) println(« Monde! ») // imprime après un délai } println(« Bonjour ») // reprise de la coroutine principale alors qu’une précédente est détenue } |
Ci-dessous le résultat suivant :
Bonjour
Monde!
Disséquons ce que fait ce code.
- Launch peut être un constructeur de coroutine. Il lance une toute nouvelle coroutine en même temps que le reste du code.
- Le retard peut être une opération de suspension spéciale. Il suspend la coroutine pendant une durée sélectionnée. La suspension d’une coroutine ne bloque pas le thread sous-jacent, cependant, cela permet à différentes coroutines de s’exécuter et d’utiliser le thread sous-jacent pour son code.
- runBlocking est en outre un constructeur de coroutine qui relie le monde non coroutine d’un main() amusant quotidien et également le code avec les coroutines à l’intérieur des accolades runBlocking. Cela peut être mis en évidence dans un IDE par ceci : CoroutineScope indique juste une fois l’accolade de curling de l’espace runBlocking.
Si vous supprimez ou oubliez runBlocking pendant ce code, vous obtiendrez un dérapage sur la décision de lancement, puisque le lancement est affirmé uniquement dans le CoroutineScope :
1 |
Référence non résolue : lancement |
Le nom runBlocking signifie que le thread qui l’exécute (dans ce scénario – le thread principal) est bloqué pour la durée donnée de l’appel, jusqu’à ce que tous les blocs de code à l’intérieur de runBlocking { … } terminent leur exécution. Vous observerez souvent que runBlocking aimait cela au plus haut niveau de l’application et très peu à l’intérieur du code réel, car les threads sont des ressources précieuses et les bloquer est inefficace.
Refactorisation de la fonction d’extraction
Extrayons le bloc de code dans le lancement dans un fichier séparé. Après avoir effectué la refactorisation d’Extract sur ce code, vous obtenez une toute nouvelle performance du modificateur de suspension. Cela peut être la suspension primaire effectuée. Les fonctions de suspension peuvent être utilisées dans des coroutines plutôt que des fonctions régulières, cependant, leur autre caractéristique est qu’elles utiliseront à leur tour différentes fonctions de suspension (comme le délai dans cet exemple) pour suspendre l’exécution d’une coroutine.
1 2 3 4 5 6 7 8 9 dix 11 |
fun main() = runBlocking { // CoroutineScope lancer { doWorld() } println(« Bonjour ») } // ceci est votre première fonction de suspension suspendre le plaisir doWorld() { retard (1000L) println(« Monde ! ») } |
Générateur de portée
En plus de la portée de coroutine fournie par différents générateurs, il est possible de déclarer votre propre portée à l’aide du générateur coroutineScope. Il crée une portée de coroutine et ne se termine pas tant que tous les enfants lancés ne sont pas terminés.
runBlocking et coroutineScope se ressemblent tous les deux car ils attendent tous les deux que leur corps et tous leurs enfants se terminent. La principale différence est que le runBlocking bloque le thread actuel en attente, tandis que coroutineScope se contente de suspendre, libérant le thread sous-jacent pour d’autres usages. En raison de cette différence, runBlocking est une fonction normale et coroutineScope est une fonction de suspension.
Vous pouvez utiliser coroutineScope à partir de n’importe quelle fonction de suspension. Par exemple, vous pouvez déplacer les journaux parallèles de Hello et World dans la fonction suspend doWorld() :
1 2 3 4 5 6 7 8 9 dix 11 12 |
fun main() = runBlocking { doWorld() } suspend fun doWorld() = coroutineScope { // this: CoroutineScope lancement { retard (1000L) println(« Monde ! ») } println(« Bonjour ») } |
Ce code imprime également :
Bonjour
Monde!
Générateur de portée et concurrence
Le générateur coroutineScope peut être utilisé dans n’importe quelle fonction de suspension pour effectuer plusieurs processus simultanés. Lançons deux coroutines simultanées dans une fonction de suspension doWorld :
1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15 16 17 18 19 |
// Exécute séquentiellement doWorld suivi de « Done » fun main() = runBlocking { doWorld() println(« Terminé ») } // Exécute simultanément les deux sections suspend fun doWorld() = coroutineScope { // this: CoroutineScope lancement { retard (2000L) println(« Monde 2 ») } lancement { retard (1000L) println(« Monde 1 ») } println(« Bonjour ») } |
Les deux fonctions de code à l’intérieur des blocs launch { … } s’exécutent en parallèle, avec World1 imprimé en premier, après une seconde à partir du début, et World2 imprimé ensuite, après deux secondes à partir du début. coroutineScope dans le bloc doWorld ne se termine qu’une fois les deux blocs terminés, donc doWorld renvoie et permet à la chaîne Done d’être imprimée uniquement après cela.
Un travail explicite
Un générateur de coroutine de lancement renvoie un objet de Job qui est un handle vers la coroutine lancée et peut être utilisé pour attendre de force son achèvement. Par exemple, vous pouvez attendre la fin de la coroutine enfant, puis imprimer la chaîne « Terminé » imprimera :
1 2 3 4 5 6 7 8 |
val job = launch { // lance une nouvelle coroutine et garde une référence de ce Job retard (1000L) println(« Monde ! ») } println(« Bonjour ») job.join() // attend la fin de la coroutine enfant println(« Terminé ») |
Et les coroutines sont légères
1 2 3 4 5 6 7 8 9 dix 11 12 13 |
importer kotlinx.coroutines.* //début de l’échantillon fun main() = runBlocking { repeat(100_000) { // lance un grand nombre de coroutines lancement { retard (5000L) imprimer(« . ») } } } //fin de l’échantillon |
Le code ci-dessus lance 100 000 coroutines et après 5 secondes, chaque coroutine imprime un point.
Maintenant, essayez cela avec les threads (et supprimez runBlocking, remplacez launch par thread et remplacez delay par Thread.sleep ). Ce qui se passerait? (Très probablement, votre code produira une erreur de mémoire insuffisante)
Conclusion
Le but de ce blog était de discuter brièvement de ce que sont les mécanismes de coroutines de Kotlin, comment ils fonctionnent et comment nous les utiliserons comme alternative à la programmation asynchrone à utiliser dans nos projets quotidiens. Nous pensons que vous avez maintenant une meilleure compréhension du concept.