🚧 Attention, peinture fraîche !

Cette page a été traduite par une seule personne et n'a pas été relue et vérifiée par quelqu'un d'autre ! Les informations peuvent par exemple être erronées, être formulées maladroitement, ou contenir d'autres types de fautes.

L'écosystème asynchrone

Actuellement, Rust ne fournit que l'essentiel pour écrire du code asynchrone. En particulier, les exécuteurs, les tâches, les réacteurs, les combinateurs, et les futures et les traits de bas-niveau d'entrée/sortie ne sont pas encore fournis par la bibliothèque standard. Mais en attendant, les écosystèmes asynchrones fournis par la communauté répondent à ce besoin.

L'équipe en charge des fondations de l'asynchrone est intéressée par le développement dans le livre sur l'asynchrone pour couvrir plusieurs environnements d'exécution. Si vous êtes intéressé pour contribuer à ce projet, veuillez vous rendre sur Zulip.

Les environnements d'exécution asynchrone

Les environnements d'exécution asynchrones sont des bibliothèques utilisées pour exécuter des applications asynchrones. Les environnements d'exécution embarquent généralement ensemble un réacteur avec un ou plusieurs exécuteurs. Les réacteurs fournissent des mécanismes d'abonnement pour les évènements externes, comme les entrées/sorties asynchrones, la communication entre les processus, et les temporisations. Dans un environnement d'exécution asynchrone, les abonnés sont typiquement des futures qui représentent les opérations d'entrées/sorties de bas-niveau. Les exécuteurs gèrent la planification et l'exécution des tâches. Ils assurent le suivi les tâches en cours d'exécution et celles qui sont suspendues, l'appel des futures jusqu'à ce qu'elles terminent, et réaniment les tâches lorsqu'elles peuvent progresser. Le mot "exécuteur" est souvent permuté avec "l'environnement d'exécution". Ici, nous utilisons le mot "écosystème" pour décrire un environnement d'exécution accompagné des traits et fonctionnalités compatibles.

Les crates asynchrones fournies par la communauté

La crate Futures

La crate futures contient les traits et les fonctions utiles pour écrire du code asynchrone. Cela comprend les traits Stream, Sink, AsyncRead, et AsyncWrite, et des utilitaires comme les combinateurs. Ces utilitaires et ces traits pourraient éventuellement faire partie un jour de la bibliothèque standard.

Les futures ont leur propre exécuteur, mais pas son propre réacteur, donc cela ne prend pas en charge l'exécution d'entrées/sorties asynchrones ou de futures de temporisation. C'est pour cette raison que ce n'est pas considéré comme un environnement d'exécution complet. Il est courant d'employer les utilitaires de futures avec un exécuteur d'une autre crate.

Les environnements d'exécution asynchrones populaires

Il n'y a pas d'environnement d'exécution asynchrone dans la bibliothèque standard, et aucune n'est officiellement recommandée. Les crates suivantes offrent des environnement d'exécution populaires.

  • Tokio : un écosystème asynchrone populaire pour des cadriciels travaillant avec HTTP, gRPC et du traçage.
  • async-std : une crate qui fournit des équivalents asynchrones aux composants de la bibliothèque standard.
  • smol : un environnement d'exécution asynchrone, minimisé et simplifié.

La compatibilité des écosystèmes

Toutes les applications, cadriciels, et bibliothèques asynchrones ne sont pas compatibles entre elles, ou avec tous les systèmes d'exploitation ou plateformes. La plupart du code asynchrone peut être utilisé avec n'importe quel écosystème, mais certains cadriciels et bibliothèques nécessitent l'utilisation d'un écosystème précis. Les contraintes d'un écosystème ne sont pas toujours documentées, mais quelques méthodes empiriques pour déterminer si une bibliothèque, un trait, ou une fonction dépends d'un écosystème précis.

Tout code asynchrone qui interagit avec des entrées/sorties, temporisations, communication inter-processus, ou des tâches asynchrones dépend généralement d'un exécuteur ou réacteur asynchrone. Tous les autres codes asynchrones, comme les expressions, combinateurs, types de sychronisation, et les Stream asynchrones sont généralement indépendants des écosystèmes, à condition que toutes les futures imbriquées sont aussi indépendantes de tout écosystème. Avant de commencer un projet, il est recommandé de rechercher les cadriciels et bibliothèques asynchrones que vous aurez besoin pour vous assurer la compatibilité entre eux et avec l'environnement d'exécution que vous avez choisi.

En particulier, Tokio utilise le réacteur mio et définit ses propres versions des traits d'entrées/sorties asynchrones, y compris AsyncRead et AsyncWrite. Seul, il n'est pas compatible avec async-std et smol, qui reposent sur la crate async-executor, et les traits AsyncRead et AsyncWrite sont définis dans futures.

Les pré-requis d'environnement d'exécution en conflit peuvent parfois être résolus avec des couches de compatibilité qui vous permettent d'appeler du code écrit pour un environnement d'exécution dans un autre. Par exemple, la crate async_compat fournit une couche de compatibilité entre Tokio et les autres environnements d'exécution.

Les bibliothèques qui exposent des APIs asynchrones ne devraient pas dépendre d'un exécuteur ou d'un réacteur en particulier, à moins qu'ils aient besoin de créer des tâches ou de définir leurs propres entrées/sorties asynchrones ou des futures de temporisation. Dans l'idéal, seuls les binaires devraient être responsables de la planification et de l'exécution des tâches.

Les exécuteurs mono-processus versus multi-processus

Les exécuteurs asynchrones peuvent être mono-processus ou multi-processus. Par exemple, la crate async-executor a deux LocalExecutor mono-processus et un Executor multi-processus.

Les exécuteurs multi-processus permettent de faire progresser plusieurs tâches en simultané. Cela peut accélérer considérablement l'exécution pour les charges de travail avec beaucoup de tâches, mais la synchronisation des données entre les tâches est habituellement moins rentable. Il est recommandé de mesurer les performances de votre application lorsque vous choisissez entre un environnement d'exécution mono-processus et multi-processus.

Les tâches peuvent être exécutées soit sur le processus qui les a créés, ou sur processus séparé. Les environnements d'exécution asynchrones fournissent souvent des fonctionnalités pour créer des tâches sur des processus séparés. Même si les tâches sont exécutées sur des processus séparés, ils ne doivent toujours pas être bloquants. Pour pouvoir planifier l'exécution des tâches sur un exécuteur multi-processus, elles doivent être aussi être Send. Certains environnements d'exécution fournissent des fonctions pour créer des tâches qui ne sont pas Send, ce qui permet de s'assurer que les tâches sont exécutées sur le processus qui les ont créés. Ils peuvent également fournir des fonctions pour créer des tâches bloquantes sur des processus dédiés, ce qui est pratique pour exécuter du code synchrone bloquant des autres bibliothèques.