diff --git a/FRENCH/examples-sources/01_04_async_await_primer/Cargo.toml b/FRENCH/examples-sources/01_04_async_await_primer/Cargo.toml new file mode 100644 index 00000000..74644d11 --- /dev/null +++ b/FRENCH/examples-sources/01_04_async_await_primer/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "example_01_04_async_await_primer" +version = "0.1.0" +authors = ["Taylor Cramer "] +edition = "2018" + +[lib] + +[dependencies] +futures = "0.3" diff --git a/FRENCH/examples-sources/01_04_async_await_primer/src/lib.rs b/FRENCH/examples-sources/01_04_async_await_primer/src/lib.rs new file mode 100644 index 00000000..1a2c14eb --- /dev/null +++ b/FRENCH/examples-sources/01_04_async_await_primer/src/lib.rs @@ -0,0 +1,75 @@ +#![cfg(test)] + +use futures::executor::block_on; + +mod first { +// ANCHOR: hello_world +// `block_on` blocks the current thread until the provided future has run to +// completion. Other executors provide more complex behavior, like scheduling +// multiple futures onto the same thread. +use futures::executor::block_on; + +async fn hello_world() { + println!("hello, world!"); +} + +fn main() { + let future = hello_world(); // Nothing is printed + block_on(future); // `future` is run and "hello, world!" is printed +} +// ANCHOR_END: hello_world + +#[test] +fn run_main() { main() } +} + +struct Song; +async fn learn_song() -> Song { Song } +async fn sing_song(_: Song) {} +async fn dance() {} + +mod second { +use super::*; +// ANCHOR: block_on_each +fn main() { + let song = block_on(learn_song()); + block_on(sing_song(song)); + block_on(dance()); +} +// ANCHOR_END: block_on_each + +#[test] +fn run_main() { main() } +} + +mod third { +use super::*; +// ANCHOR: block_on_main +async fn learn_and_sing() { + // Wait until the song has been learned before singing it. + // We use `.await` here rather than `block_on` to prevent blocking the + // thread, which makes it possible to `dance` at the same time. + let song = learn_song().await; + sing_song(song).await; +} + +async fn async_main() { + let f1 = learn_and_sing(); + let f2 = dance(); + + // `join!` is like `.await` but can wait for multiple futures concurrently. + // If we're temporarily blocked in the `learn_and_sing` future, the `dance` + // future will take over the current thread. If `dance` becomes blocked, + // `learn_and_sing` can take back over. If both futures are blocked, then + // `async_main` is blocked and will yield to the executor. + futures::join!(f1, f2); +} + +fn main() { + block_on(async_main()); +} +// ANCHOR_END: block_on_main + +#[test] +fn run_main() { main() } +} diff --git a/FRENCH/examples-sources/Cargo.toml b/FRENCH/examples-sources/Cargo.toml index 38cf9482..e98c758e 100644 --- a/FRENCH/examples-sources/Cargo.toml +++ b/FRENCH/examples-sources/Cargo.toml @@ -1,3 +1,4 @@ [workspace] members = [ + "01_04_async_await_primer", ] diff --git a/FRENCH/examples/01_04_async_await_primer/Cargo.toml b/FRENCH/examples/01_04_async_await_primer/Cargo.toml new file mode 100644 index 00000000..74644d11 --- /dev/null +++ b/FRENCH/examples/01_04_async_await_primer/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "example_01_04_async_await_primer" +version = "0.1.0" +authors = ["Taylor Cramer "] +edition = "2018" + +[lib] + +[dependencies] +futures = "0.3" diff --git a/FRENCH/examples/01_04_async_await_primer/src/lib.rs b/FRENCH/examples/01_04_async_await_primer/src/lib.rs new file mode 100644 index 00000000..16f41a5b --- /dev/null +++ b/FRENCH/examples/01_04_async_await_primer/src/lib.rs @@ -0,0 +1,78 @@ +#![cfg(test)] + +use futures::executor::block_on; + +mod first { +// ANCHOR: hello_world +// `block_on` bloque le processus en cours jusqu'à ce que la future qu'on lui +// donne ait terminé son exécution. Les autres exécuteurs ont un comportement +// plus complexe, comme par exemple ordonnancer plusieurs futures sur le même +// processus. +use futures::executor::block_on; + +async fn salutations() { + println!("salutations !"); +} + +fn main() { + let future = salutations(); // rien n'est pas affiché + block_on(future); // `future` est exécuté et "salutations !" est affiché +} +// ANCHOR_END: hello_world + +#[test] +fn run_main() { main() } +} + +struct Chanson; +async fn apprendre_chanson() -> Chanson { Chanson } +async fn chanter_chanson(_: Chanson) {} +async fn danser() {} + +mod second { +use super::*; +// ANCHOR: block_on_each +fn main() { + let chanson = block_on(apprendre_chanson()); + block_on(chanter_chanson(chanson)); + block_on(danser()); +} +// ANCHOR_END: block_on_each + +#[test] +fn run_main() { main() } +} + +mod third { +use super::*; +// ANCHOR: block_on_main +async fn apprendre_et_chanter() { + // Attends (await) que la chanson soit apprise avant de la chanter. + // Nous utilisons ici `.await` plutôt que `block_on` pour éviter de bloquer + // le processus, ce qui rend possible de `danser` en même temps. + let chanson = apprendre_chanson().await; + chanter_chanson(chanson).await; +} + +async fn async_main() { + let f1 = apprendre_et_chanter(); + let f2 = danser(); + + // `join!` se comporte comme `.await`, mais permet d'attendre plusieurs + // futures en concurrence. Si nous avions bloqué temporairement dans la + // future `apprendre_et_chanter`, la future `danser` aurais pris le relais + // dans le processus d'exécution en cours. Si `danser` se bloque aussi, + // `apprendre_et_chanter` pourra continuer dans le processus en cours. Si + // les deux futures sont bloquées, et bien `async_main` est bloqué et va en + // informer son exécuteur. + futures::join!(f1, f2); +} + +fn main() { + block_on(async_main()); +} +// ANCHOR_END: block_on_main + +#[test] +fn run_main() { main() } +} diff --git a/FRENCH/examples/Cargo.toml b/FRENCH/examples/Cargo.toml index 38cf9482..e98c758e 100644 --- a/FRENCH/examples/Cargo.toml +++ b/FRENCH/examples/Cargo.toml @@ -1,3 +1,4 @@ [workspace] members = [ + "01_04_async_await_primer", ] diff --git a/FRENCH/src/01_getting_started/04_async_await_primer.md b/FRENCH/src/01_getting_started/04_async_await_primer.md new file mode 100644 index 00000000..7041e9bb --- /dev/null +++ b/FRENCH/src/01_getting_started/04_async_await_primer.md @@ -0,0 +1,172 @@ + + +# Introduction à `async` et `await` + + + +Le `async` et `await` sont les outils intégrés dans Rust pour écrire des +fonctions asynchrones qui ressemblent à du code synchrone. `async` transforme +un bloc de code en une machine à états qui implémente le trait `Future`. Alors +que l'appel à une fonction bloquante dans une méthode synchrone va bloquer tout +le processus, les `Future`s bloquées céderont le contrôle du processus, +permettant aux autres `Future`s de s'exécuter. + + + +Ajoutons quelques dépendances au fichier `Cargo.toml` : + + + +```toml +{{#include ../../examples/01_04_async_await_primer/Cargo.toml:9:10}} +``` + + + +Pour créer une fonction asynchrone, vous pouvez utiliser la syntaxe +`async fn` : + + + +```rust,edition2018 +async fn faire_quelquechose() { /* ... */ } +``` + + + +La valeur retournée par `async fn` est une `Future`. Pour que quelque chose se +produise, la `Future` a besoin d'être exécutée avec un exécuteur. + + + +```rust,edition2018 +{{#include ../../examples/01_04_async_await_primer/src/lib.rs:hello_world}} +``` + + + +Dans une `async fn`, vous pouvez utiliser `.await` pour attendre la fin d'un +autre type qui implémente le trait `Future`, comme le résultat d'une autre +`async fn`. Contrairement à `block_on`, `.await` ne bloque pas le processus en +cours, mais attends plutôt de manière asynchrone que la future se termine, pour +permettre aux autres tâches de s'exécuter si cette future n'est pas en mesure de +progresser actuellement. + + + +Par exemple, imaginons que nous ayons trois `async fn` : `apprendre_chanson`, +`chanter_chanson`, et `danser` : + + + +```rust,ignore +async fn apprendre_chanson() -> Chanson { /* ... */ } +async fn chanter_chanson(chanson: Chanson) { /* ... */ } +async fn danser() { /* ... */ } +``` + + + +Une façon d'apprendre, chanter, et danser serait de bloquer sur chacun : + + + +```rust,ignore +{{#include ../../examples/01_04_async_await_primer/src/lib.rs:block_on_each}} +``` + + + +Cependant, nous ne profitons pas de performances optimales de cette manière — +nous ne faisons qu'une seule chose à fois ! Il faut que nous apprenions la +chanson avant de pouvoir la chanter, mais il reste possible de danser en même +temps qu'on apprends et qu'on chante la chanson. Pour pouvoir faire cela, nous +pouvons créer deux `async fn` qui peuvent être exécutés en concurrence : + + + +```rust,ignore +{{#include ../../examples/01_04_async_await_primer/src/lib.rs:block_on_main}} +``` + + + +Dans cet exemple, la chanson doit être apprise avant de chanter la chanson, +mais l'apprentissage et le chant peuvent se dérouler en même temps qu'on +danse. Si nous avions utilisé `block_on(apprendre_chanson())` plutôt que +`apprendre_chanson().await` dans `apprendre_et_chanter`, le processus n'aurait +rien pu faire tant que `apprendre_chanson` s'exécutait. Cela aurait rendu +impossible de pouvoir danser en même temps. En attendant la future +`apprendre_chanson`, grâce à `await`, nous permettons aux autres tâches de +prendre le relais dans le processus en cours d'exécution lorsque +`apprendre_chanson` est bloqué. Cela permet d'exécuter plusieurs futures +jusqu'à leur fin de manière concurrente au sein du même processus. diff --git a/FRENCH/src/SUMMARY.md b/FRENCH/src/SUMMARY.md index beeca743..6c7d96aa 100644 --- a/FRENCH/src/SUMMARY.md +++ b/FRENCH/src/SUMMARY.md @@ -1,3 +1,5 @@ # Table des matières + - [Introduction à `async` et `await`](01_getting_started/04_async_await_primer.md) + [Traduction des termes](translation-terms.md)