Formation > Blog > Langage > Comment programmer de manière asynchrone sur Rust ?

La programmation asynchrone dans Rust est une véritable bête de somme pour les applications modernes. En maitriser tous les arcanes est un atout non négligeable si vous êtes vous-même développeur. Dans cet article, on rentre dans le vif du sujet.

Sommaire

Avant de se lancer

L’équipe Ambient IT

Qu’est-ce que la programmation asynchrone ?

Si l’on devait faire un parallèle, la programmation asynchrone, c’est un peu comme jongler avec plusieurs balles en même temps.

En langage Rust cela veut dire utiliser les futures ainsi que la syntaxe async/await qui permet de gérer plusieurs tâches en même temps ou presque.

En quoi l’asynchrone diffère-t-il du synchrone ?

En mode synchrone, vous lancez une tâche, vous attendez qu’elle finisse, vous passez à la suivante, etc.

Avec la méthode asynchrone, vous pouvez lancer une tâche, mettre la réponse en attente et en faire une autre dans la foulée. C’est une différence clé pour comprendre en quoi c’est une sacrée avancée en termes de performance et de réactivité.

Pourquoi choisir l’asynchrone en Rust ?

Rust est sans aucun doute le meilleur langage pour l’asynchrone, car il dispose de « zero-cost abstractions ».

Vous êtes donc assuré de ne pas avoir de surcoût inutile d’exécution. C’est un gros plus pour les applications nécessitant de hautes performances.

Qu’est-ce que async/await en Rust ?

async transforme une fonction en une Future, un type représentant une valeur qui sera disponible éventuellement. await est utilisé pour attendre le résultat d’une Future sans bloquer le thread.

Pour bien comprendre la programmation Asynchrone, il faut comprendre les commandes :

  • async transforme une fonction en une future, un type représentant une valeur qui sera disponible dans le… futur
  • await est utilisé pour faire patienter le résultat d’une future sans bloquer le thread.

Futures, tâches, executors : quels sont les concepts clés ?

Les Futures sont au cœur de l’asynchrone en Rust. Une tâche est une Future qui est exécutée par un executor, qui gère la répartition des tâches sur les Threads disponibles.

Un des concepts phares est de poller un future. Il s’agit de vérifier si la valeur est prête ou si elle doit être de nouveau mise en attente.

L’executor est lui responsable de prendre une future et l’exécuter jusqu’à ce qu’elle soit bien complète. En d’autres termes, il gère le cycle de vie des futures et assure leur progression.

Comment Rust implémente-t-il l’asynchrone ?

Ici, tout tourne autour du trait Future et de la pile de runtime asynchrone choisie. Les plus communes sont Tokio et async-std, mais il en existe plein d’autres.

Runtimes et Librairies

Tokio et async-std sont les deux runtimes les plus populaires. Ils offrent des environnements d’exécution pour les Futures et des bibliothèques de composants asynchrones

Tokio est souvent préféré par les développeurs, car considéré comme plus performant. Il dispose en tout cas d’un environnement plus mature pour les applications réseau.

Créer un runtine asynchrone avec Tokio

Créer un runtime asynchrone avec Tokio est une tâche beaucoup plus simple qu’il n’y parait, alors, laissez-vous guider.

Prérequis

Vous aurez besoin de Rust installé sur votre machine et savoir comment l’utiliser

Étape 1 : mise en place du projet

Vous devez d’abord créer un nouveau projet dans Rust en utilisant cargo.

cargo new my_async_app
cd my_async_app

Étape 2 : ajout des dépendances

Il faut maintenant modifier le fichier Cargo.toml pour inclure Tokio en tant que dépendance. Je vous conseille simplement d’activer la fonction « full » qui vous donnera accès aux utilitaires les plus communément utilisés.

[dependencies]
tokio = { version = "1", features = ["full"] }

Étape 3 : écrire du code asynchrone

Ouvrez le fichier src/main.rs et changez son contenu par le code suivant :

use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() {
    println!("Starting the async runtime...");

    tokio::spawn(async {
        println!("This task runs concurrently with the delay.");
    });

    sleep(Duration::from_secs(3)).await;
    println!("After a 3-second delay");

    println!("Exiting the program.");
}

Ce code vous permet d’initialiser un runtime Tokio et d’exécuter un bloc asynchrone :

  • #[tokio::main] transforme la fonction main en point d’entrée asynchrone de l’application
  • tokio::spawn crée une tache asynchrone qui s’exécute en même temps que d’autres parties
  • sleep est une opération asynchrone qui cède le contrôle sans bloquer le thread en simulant un délai

Étape 4 : lancer l’application

Il ne vous reste plus qu’à utiliser Cargo pour lancer votre application.

cargo run

Cela devrait vous permettre de voir la sortie qui montre vos tâches asynchrones, y compris les délais :

Starting the async runtime...
This task runs concurrently with the delay.
After a 3-second delay
Exiting the program. 

Cette méthode avec Tokio est particulièrement utile pour le déploiement d’applications qui demande des grosses performances et une excellente évolutivité.

Dans mon exemple, je vous donne une application asynchrone assez basique (bien que fonctionnelle) mais Tokio vous donne très facilement la possibilité d’étendre cette application en y ajoutant des opérations plus complexes.

UNE QUESTION ? UN PROJET ? UN AUDIT DE CODE / D'INFRASTRUCTURE ?

Pour vos besoins d’expertise que vous ne trouvez nulle part ailleurs, n’hésitez pas à nous contacter.

ILS SE SONT FORMÉS CHEZ NOUS

partenaire sncf
partenaire hp
partenaire allianz
partenaire sfr
partenaire engie
partenaire boursorama
partenaire invivo
partenaire orange
partenaire psa
partenaire bnp
partenaire sncf
partenaire hp
partenaire allianz
partenaire sfr
partenaire engie
partenaire boursorama
partenaire invivo
partenaire orange
partenaire psa
partenaire bnp