Pourquoi voudrais-je utiliser des coroutines Kotlin?
Il semble que la bibliothèque RxKotlin soit beaucoup plus polyvalente. Les coroutines de Kotlin semblent nettement moins puissantes et plus lourdes à utiliser en comparaison.
Je fonde mon opinion sur les coroutines de cette présentation d’Andrey Breslav (JetBrains): https://www.youtube.com/watch?v=4W3ruTWUhpw
Le diaporama de la discussion est accessible ici: https://www.slideshare.net/abreslav/jvmls-2016-coroutines-in-kotlin
EDIT (grâce à @hotkey):
Meilleure source sur l'état actuel des coroutines: https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md
Il y a deux parties dans Rx; le modèle Observable et un ensemble solide d’opérateurs pour les manipuler, les transformer et les combiner. Le modèle Observable, par lui-même, ne fait pas beaucoup. Même avec Coroutines; c'est juste un autre paradigme pour traiter de l'asynchronisme. Vous pouvez comparer les avantages/inconvénients des rappels, Observable et des routines pour résoudre un problème donné, mais vous ne pouvez pas comparer un paradigme avec une bibliothèque complète. C'est comme comparer une langue avec un framework.
Comment les Koutlin sont-elles meilleures que RxKotlin? N'a pas encore utilisé de coroutines, mais cela ressemble à async/wait en C #. Vous venez d'écrire du code séquentiel, tout est aussi simple que d'écrire du code synchrone ... sauf qu'il s'exécute de manière asynchrone. C'est plus facile à saisir.
Pourquoi voudrais-je utiliser des coroutines Kotlin? Je vais répondre par moi-même. La plupart du temps, je vais m'en tenir à Rx, car je privilégie une architecture événementielle. Toutefois, si j’écris du code séquentiel et que j’ai besoin d’appeler une méthode asynchrone au milieu, j’utiliserai avec plaisir des coroutines pour que cela reste ainsi et évitera de tout emballer dans Observable.
Edit: Maintenant que j'utilise des routines, il est temps de faire une mise à jour.
RxKotlin est juste un sucre syntaxique pour utiliser RxJava dans Kotlin, je vais donc parler de RxJava et non de RxKotlin dans la suite. Les coroutines sont un levier plus bas et un concept plus général que RxJava, elles servent d’autres cas d’utilisation. Cela dit, il existe un cas d'utilisation où vous pouvez comparer RxJava et les coroutines (channel
), il transmet les données de manière asynchrone. Coroutines a un net avantage sur RxJava ici:
subscribeOn()
et ObserveOn()
prêtent à confusion. Chaque coroutine reçoit un contexte de fil et retourne au contexte parent. Pour un canal, les deux côtés (producteur, consommateur) s'exécutent dans leur propre contexte. Les coroutines sont plus intuitives sur l'affectation de threads ou de pool de threads.yield
), hiérarchiser (select
), paralléliser (plusieurs producer
/actor
sur channel
) ou verrouiller la ressource (Mutex
) pour un calcul donné. Cela n’importe peut-être pas sur le serveur (où RxJava est arrivé en premier), mais sur un environnement aux ressources limitées, ce niveau de contrôle peut être requis.send()
to channel est une fonction suspensive suspendue lorsque la capacité du canal est atteinte. C'est une contre-pression hors du commun donnée par la nature. Vous pouvez également offer()
to channel, auquel cas l'appel ne sera jamais suspendu mais retournera false
si le canal est plein, reproduisant ainsi onBackpressureDrop()
de RxJava. Vous pouvez également écrire votre propre logique de contrepression personnalisée, ce qui ne sera pas difficile avec les coroutines, surtout si vous faites de même avec RxJava.Il existe un autre cas d'utilisation, où les coroutines brillent et cela répondra à votre deuxième question "Pourquoi voudrais-je utiliser des coroutines Kotlin?". Les Coroutines sont le remplacement parfait pour les threads d'arrière-plan ou AsyncTask
(Android). C'est aussi simple que launch { someBlockingFunction() }
. Bien sûr, vous pouvez aussi réaliser cela avec RxJava, en utilisant Schedulers
et Completable
peut-être. Vous n'utiliserez pas (ou peu) le modèle Observer et les opérateurs qui sont la signature de RxJava, ce qui indique que ce travail est hors de portée pour RxJava. La complexité de RxJava (une taxe inutile ici) rendra votre code plus verbeux et moins propre que la version de Coroutine.
La lisibilité est importante. À cet égard, les approches RxJava et coroutines diffèrent beaucoup. Les Coroutines sont plus simples que RxJava. Si vous n'êtes pas à l'aise avec map()
, flatmap()
et la programmation réactive fonctionnelle en général, les manipulations de coroutines sont plus faciles, impliquant des instructions de base: for
, if
, try/catch
... Mais je trouve personnellement que le code de coroutine est plus difficile à comprendre pour des tâches non triviales. En particulier, cela implique davantage d'imbrication et d'indentation, alors que la chaîne d'opérateurs dans RxJava garde tout en ligne. La programmation fonctionnelle rend le traitement plus explicite. En plus de cela, RxJava peut résoudre des transformations complexes avec quelques opérateurs standard de leur riche ensemble d'opérateurs (OK, beaucoup trop riche). RxJava brille lorsque vous avez des flux de données complexes nécessitant beaucoup de combinaisons et de transformations.
J'espère que ces considérations vous aideront à choisir le bon outil en fonction de vos besoins.
Les coroutines de Kotlin sont différentes de Rx. Il est difficile de les comparer de pommes à pommes, car les coroutines de Kotlin sont une fonctionnalité de langage fin (avec juste quelques concepts de base et quelques fonctions de base pour les manipuler), tandis que Rx est une bibliothèque assez lourde avec une assez grande variété de opérateurs prêts à l'emploi. Les deux sont conçus pour résoudre un problème de programmation asynchrone, mais leur solution est très différente:
Rx est livré avec un style de programmation fonctionnel particulier qui peut être implémenté dans pratiquement n'importe quel langage de programmation sans support du langage lui-même. Cela fonctionne bien lorsque le problème à résoudre se décompose facilement en une séquence d'opérateurs standard et pas si bien autrement.
Les coroutines de Kotlin fournissent une fonctionnalité de langage qui permet aux rédacteurs de bibliothèque d'implémenter divers styles de programmation asynchrones, notamment le style réactif fonctionnel (Rx). Avec Koutlin coroutines, vous pouvez également écrire votre code asynchrone dans un style impératif, dans un style promesse/futur, dans un style acteur, etc.
Il est plus approprié de comparer Rx avec certaines bibliothèques spécifiques implémentées à partir de coroutines Kotlin.
Prenons bibliothèque kotlinx.coroutines à titre d'exemple. Cette bibliothèque fournit un ensemble de primitives telles que async/await
et des canaux qui sont généralement intégrés à d’autres langages de programmation. Il prend également en charge des acteurs légers et sans avenir. Vous pouvez en savoir plus dans le Guide de kotlinx.coroutines par exemple .
Chaînes fournies par kotlinx.coroutines
peut remplacer ou augmenter Rx dans certains cas d'utilisation. Il existe un Guide des flux réactifs avec des routines qui approfondit les similitudes et les différences avec Rx.
La conversation/doc que vous avez liée ne parle pas de chaînes. Les canaux sont ce qui comble le fossé entre votre compréhension actuelle des coroutines et la programmation événementielle.
Avec les coroutines et les canaux, vous pouvez effectuer une programmation événementielle comme vous le faites probablement avec rx, mais vous pouvez le faire avec un code d’aspect synchrone et sans autant d’opérateurs "personnalisés".
Si vous voulez mieux comprendre cela, je suggère de regarder en dehors de Kotlin, où ces concepts sont plus matures et raffinés (et non expérimentaux). Regarder core.async
de Clojure, vidéos de Rich Hickey, publications et discussions connexes.