Programmation asynchrone en Ruby : présentation de la gem concurrent-ruby (Partie 3)

Après avoir découvert les outils natifs en Ruby, nous allons passer en revue la gem concurrent-ruby. Cette gem affirme être la seule avec un modèle de gestion de la mémoire réalisant des opérations atomiques, garantissant un comportement thread-safe pour toutes ses fonctionnalités.

concurrent-ruby est principalement un framework permettant de manipuler des threads de différentes saveurs.

Le module Async

« Lorsque ce module est inclus dans une classe, les objets de la classe deviennent intrinsèquement asynchrones. Chaque objet obtient son propre thread d’arrière-plan dans lequel réaliser ses appels de méthodes asynchrones. Les appels de méthodes asynchrones sont exécutés un par un dans l’ordre où ils sont reçus. »

« Note importante : la garantie thread-safe tient seulement quand les appels de méthodes asynchrones ne sont pas mélangés à des appels directs aux méthodes. Utilisez uniquement des appels directs aux méthodes quand l’objet est utilisé exclusivement par un seul processus. Utilisez uniquement async et await quand l’objet est partagé entre plusieurs threads. »

La classe Future

« Un objet Future représente la promesse d’achever une action à un moment donné dans l’avenir. L’idée derrière une Future est d’envoyer une opération dans une exécution asynchrone, continuer à faire d’autres choses, puis retourner et récupérer le résultat de l’opération asynchrone à un moment ultérieur. »

Notez qu’on peut aussi appeler Future.new à la place de Future.execute et .execute plus tard sur l’objet pour en différer le départ. Les Futures ont différents états tout au long de leur vie (:unscheduled, :pending, :processing, :rejected et :fulfilled) et sont considérées complétées lorsque l’état est soit :rejected soit :fulfilled.

Il existe même un outil dataflow permettant d’exécuter du code uniquement lorsque plusieurs Futures sont considérées complétées.

La classe Promise

C’est une implémentation complètement inspirée de JavaScript. « Les Promises sont semblables aux Futures et partagent beaucoup des mêmes comportements. Les Promises sont cependant beaucoup plus robustes. Elles peuvent être chaînées dans une structure en arbre où chaque Promise peut avoir zéro ou plus d’enfants. Les Promises sont chaînées en utilisant la méthode then. Le résultat d’un appel à then est toujours une autre Promise. Les Promises sont résolues de manière asynchrone (par rapport au fil principal) mais dans un ordre strict : les parents sont garantis d’être résolus devant leurs enfants, les enfants avant leurs frères et sœurs plus jeunes. La méthode then prend deux paramètres: un bloc facultatif à exécuter lors de la résolution du parent et un appel facultatif à exécuter en cas d’échec du parent. Le résultat de chaque promesse est transmis à chacun de ses enfants jusqu’à la résolution de l’arbre. Quand une promesse est rejetée, tous ses enfants seront rejetés et recevront la raison. »

Il faut reconnaitre que c’est touffu. En même temps ça fait plus de choses que les Futures :

Sachez que le retour de la dernière opération d’un then sera passé à la Promise suivante, attention inline.

Les états et les méthodes des Promises sont semblables à ceux des Futures (:unscheduled, :pending, :processing, :rejected et :fulfilled, .complete? etc).

Et au delà

Il existe tout un tas d’outils que je vais me garder de présenter en détail, ce serait trop long. Il existe des classes pour planifier des tâches et appeler du code périodiquement, des structures de données thread-safe (array, hash, map, tuple et une tonne d’autres) et plus encore.

La gem concurrent-ruby-edge va encore plus loin avec des fonctionnalités instables qui sont en train d’être regroupées dans un framework. Mais celle là ne sera pas prête d’être prod-ready avant un moment.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.