From a1bc4539ec52a34a0e9bead1ec7af7d17889e7bf Mon Sep 17 00:00:00 2001 From: Jimskapt Date: Tue, 14 Dec 2021 19:07:43 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=8C=90=20Translate=20ch01-02=20in=20f?= =?UTF-8?q?rench.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../01_02_why_async/Cargo.toml | 10 + .../01_02_why_async/src/lib.rs | 47 +++ FRENCH/examples-sources/Cargo.toml | 1 + FRENCH/examples/01_02_why_async/Cargo.toml | 10 + FRENCH/examples/01_02_why_async/src/lib.rs | 39 +++ FRENCH/examples/Cargo.toml | 1 + FRENCH/src/01_getting_started/02_why_async.md | 318 ++++++++++++++++++ FRENCH/src/SUMMARY.md | 2 + FRENCH/src/translation-terms.md | 19 ++ 9 files changed, 447 insertions(+) create mode 100644 FRENCH/examples-sources/01_02_why_async/Cargo.toml create mode 100644 FRENCH/examples-sources/01_02_why_async/src/lib.rs create mode 100644 FRENCH/examples/01_02_why_async/Cargo.toml create mode 100644 FRENCH/examples/01_02_why_async/src/lib.rs create mode 100644 FRENCH/src/01_getting_started/02_why_async.md diff --git a/FRENCH/examples-sources/01_02_why_async/Cargo.toml b/FRENCH/examples-sources/01_02_why_async/Cargo.toml new file mode 100644 index 00000000..76519f21 --- /dev/null +++ b/FRENCH/examples-sources/01_02_why_async/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "example_01_02_why_async" +version = "0.1.0" +authors = ["Taylor Cramer "] +edition = "2018" + +[lib] + +[dev-dependencies] +futures = "0.3" diff --git a/FRENCH/examples-sources/01_02_why_async/src/lib.rs b/FRENCH/examples-sources/01_02_why_async/src/lib.rs new file mode 100644 index 00000000..64758e4f --- /dev/null +++ b/FRENCH/examples-sources/01_02_why_async/src/lib.rs @@ -0,0 +1,47 @@ +#![cfg(test)] + +use { + futures::{ + executor::block_on, + join, + }, + std::thread, +}; + +fn download(_url: &str) { + // ... +} + +#[test] +// ANCHOR: get_two_sites +fn get_two_sites() { + // Spawn two threads to do work. + let thread_one = thread::spawn(|| download("https://www.foo.com")); + let thread_two = thread::spawn(|| download("https://www.bar.com")); + + // Wait for both threads to complete. + thread_one.join().expect("thread one panicked"); + thread_two.join().expect("thread two panicked"); +} +// ANCHOR_END: get_two_sites + +async fn download_async(_url: &str) { + // ... +} + +// ANCHOR: get_two_sites_async +async fn get_two_sites_async() { + // Create two different "futures" which, when run to completion, + // will asynchronously download the webpages. + let future_one = download_async("https://www.foo.com"); + let future_two = download_async("https://www.bar.com"); + + // Run both futures to completion at the same time. + join!(future_one, future_two); +} +// ANCHOR_END: get_two_sites_async + +#[test] +fn get_two_sites_async_test() { + block_on(get_two_sites_async()); +} diff --git a/FRENCH/examples-sources/Cargo.toml b/FRENCH/examples-sources/Cargo.toml index 38cf9482..f41a65ef 100644 --- a/FRENCH/examples-sources/Cargo.toml +++ b/FRENCH/examples-sources/Cargo.toml @@ -1,3 +1,4 @@ [workspace] members = [ + "01_02_why_async", ] diff --git a/FRENCH/examples/01_02_why_async/Cargo.toml b/FRENCH/examples/01_02_why_async/Cargo.toml new file mode 100644 index 00000000..76519f21 --- /dev/null +++ b/FRENCH/examples/01_02_why_async/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "example_01_02_why_async" +version = "0.1.0" +authors = ["Taylor Cramer "] +edition = "2018" + +[lib] + +[dev-dependencies] +futures = "0.3" diff --git a/FRENCH/examples/01_02_why_async/src/lib.rs b/FRENCH/examples/01_02_why_async/src/lib.rs new file mode 100644 index 00000000..a7511bf5 --- /dev/null +++ b/FRENCH/examples/01_02_why_async/src/lib.rs @@ -0,0 +1,39 @@ +#![cfg(test)] + +fn telecharger(_url: &str) { + // ... +} + +#[test] +// ANCHOR: get_two_sites +fn recuperer_deux_sites() { + // Crée deux tâches pour faire le travail. + let premiere_tache = std::thread::spawn(|| telecharger("https://www.foo.com")); + let seconde_tache = std::thread::spawn(|| telecharger("https://www.bar.com")); + + // Attente que les deux tâches se terminent. + premiere_tache.join().expect("la première tâche a paniqué"); + seconde_tache.join().expect("la deuxième tâche a paniqué"); +} +// ANCHOR_END: get_two_sites + +async fn telecharger_asynchrone(_url: &str) { + // ... +} + +// ANCHOR: get_two_sites_async +async fn recuperer_deux_sites_asynchrone() { + // Crée deux différentes "futures" qui, lorsqu'elles sont menée à terme, + // va télécharger les pages web de manière asynchrone. + let premier_future = telecharger_asynchrone("https://www.foo.com"); + let second_future = telecharger_asynchrone("https://www.bar.com"); + + // Exécute les deux futures en même temps jusqu'à leur fin. + futures::join!(premier_future, second_future); +} +// ANCHOR_END: get_two_sites_async + +#[test] +fn recuperer_deux_sites_asynchrone_test() { + futures::executor::block_on(recuperer_deux_sites_asynchrone()); +} diff --git a/FRENCH/examples/Cargo.toml b/FRENCH/examples/Cargo.toml index 38cf9482..f41a65ef 100644 --- a/FRENCH/examples/Cargo.toml +++ b/FRENCH/examples/Cargo.toml @@ -1,3 +1,4 @@ [workspace] members = [ + "01_02_why_async", ] diff --git a/FRENCH/src/01_getting_started/02_why_async.md b/FRENCH/src/01_getting_started/02_why_async.md new file mode 100644 index 00000000..b9c491c4 --- /dev/null +++ b/FRENCH/src/01_getting_started/02_why_async.md @@ -0,0 +1,318 @@ + + +# Pourquoi l'asynchrone ? + + + +Nous apprécions tous la façon dont Rust nous permet d'écrire rapidement des +programmes sûrs. Mais comment la programmation asynchrone s'inscrit-elle dans +cette démarche ? + + + +La programmation asynchrone, abrégé async, est un _modèle de programmation +concurrent_ pris en charge par un nombre croissant de langages de +programmation. Il vous permet d'exécuter un grand nombre de tâches concurrentes +sur un petit nombre de processus du Système d'Exploitation, tout en conservant +l'apparence et la convivialité de la programmation synchrone habituelle, grâce +à la syntaxe `async/await`. + + + +## L'asynchrone et les autres modèles de concurrence + + + +La programmation concurrente est moins mûre et moins "formalisée" que la +programmation séquentielle classique. Par conséquent, nous formulons la +concurrence différemment selon le modèle de programmation pris en charge par le +langage. +Un bref panorama des modèles de concurrence les plus populaires peut vous aider +à comprendre où se situe la programmation asynchrone dans le domaine plus large +de la programmation asynchrone : + + + +- Les **processus de l'OS** ne nécessitent aucun changement dans le modèle de + programmation, ce qui facilite l'expression de la concurrence. Cependant, la + synchronisation entre les processus peut-être difficile, et la conséquence + sur les performances est importante. Les groupes de processus peuvent réduire + certains coûts, mais pas suffisamment pour faire face à la charge de travail + d'une grosse masse d'entrées-sorties. +- La **programmation orientée évènements**, conjugué avec les _fonctions de + rappel_, peuvent être très performants, mais a tendance à produire un + contrôle de flux "non-linéaire" et verbeux. Les flux de données et les + propagations d'erreurs sont souvent difficiles à suivre. +- Les **coroutines**, comme les processus, ne nécessitent pas de changements + sur le modèle de programmation, ce qui facilite leur utilisation. Comme + l'asynchrone, elles peuvent supporter de nombreuses tâches. Cependant, elles + font abstraction des détails de bas niveau, qui sont importants pour la + programmation système et les implémentations personnalisées d'environnements + d'exécution. +- Le **modèle d'acteur** divise tous les calculs concurrents en différentes + parties que l'on appelle acteurs, qui communiquent par le biais de passage de + messages faillibles, comme dans les systèmes distribués. Le modèle d'acteur + peut être implémenté efficacement, mais il ne répondra pas à tous les + problèmes, comme le contrôle de flux et la logique de relance. + + + +En résumé, la programmation asynchrone permet des implémentations très +performantes qui sont nécessaires pour des langages bas-niveau comme Rust, tout +en offrant les avantages ergonomiques des processus et des coroutines. + + + +## L'asynchrone en Rust et dans les autres langages + + + +Bien que la programmation asynchrone soit prise en charge dans de nombreux +langages, certains détails changent selon les implémentations. L'implémentation +de Rust de async se distingue des autres langages de plusieurs manières : + + + +- Les **futures sont inertes** en Rust et progressent uniquement lorsqu'elles + sont sollicitées. Libérer une future va arrêter sa progression. +- **L'asynchrone n'a pas coût** en Rust, ce qui signifie que vous ne payez que + ce que vous utilisez. Plus précisément, vous pouvez utiliser async sans + allouer sur le tas et sans répartition dynamique, ce qui est très intéressant + pour les performances ! + Cela vous permet également d'utiliser async dans des environnements + restreints, comme les systèmes embarqués. +- **Il n'y a pas d'environnement d'exécution intégré** avec Rust. Par contre, + des environnements d'exécution sont proposés par des crates maintenues par la + communauté. +- **Les environnements d'exécution mono-processus et multi-processus** sont + disponibles en Rust, qui ont chacun leurs avantages et inconvénients. + + + +## L'asynchrone et les processus en Rust + + + +La première alternative à l'asynchrone en Rust est d'utiliser les processus du +Système d'Exploitation, soit directement via +[`std::thread`](https://doc.rust-lang.org/std/thread/), soit indirectement via +un groupe de processus. +La migration des processus vers de l'asynchrone et vice-versa nécessite +généralement un gros chantier de remaniement, autant en termes d'implémentation +et aussi (si vous écrivez une bibliothèque) toutes les interfaces exposées +publiquement. Par conséquent, vous pouvez vous épargner beaucoup de temps de +développement si vous choisissez très tôt le modèle qui convient bien à vos +besoins. + + + +Les **processus de Système d'Exploitation** sont préférables pour un petit +nombre de tâches, puisque les processus s'accompagnent d'une surcharge du +processeur et de la mémoire. Créer et basculer entre les processus est assez +gourmand, car même les processus inutilisés consomment des ressources système. +Une bibliothèque de groupe de tâches peut aider à atténuer certains coûts, mais +pas tous. Cependant, les processus vous permet de réutiliser du code synchrone +existant sans avoir besoin de changement significatif de code — il n'y a pas +besoin d'avoir de modèle de programmation en particulier. +Avec certains systèmes d'exploitation, vous pouvez aussi changer la priorité +d'un processus, ce qui peut être pratique pour les pilotes et les autres +utilisations sensibles à la latence. + + + +**L'asynchrone** permet de réduire significativement la surcharge du processeur +et de la mémoire, en particulier pour les charges de travail avec un grand +nombre de tâches liées à des entrées/sorties, comme les serveurs et les bases +de données. Pour comparaison à échelle égale, vous pouvez avoir un nombre bien +plus élevé de tâches qu'avec les processus du Système d'Exploitation, car comme +un environnement d'exécution asynchrone utilise une petite partie des (coûteux) +processus pour gérer une grande quantité de tâches (peu coûteuses). +Cependant, le Rust asynchrone produit des binaires plus gros à cause des +machines à états générés à partir des fonctions asynchrones et puisque chaque +exécutable embarque un environnement d'exécution asynchrone. + + + +Une dernière remarque, la programmation asynchrone n'est pas _meilleure_ que +les processus, c'est différent. +Si vous n'avez pas besoin de l'asynchrone pour des raisons de performance, les +processus sont souvent une alternative plus simple. + + + +### Exemple : un téléchargement concurrent + + + +Dans cet exemple, notre objectif est de télécharger deux pages web en +concurrence. Dans une application traditionnelle avec des processus nous avons +besoin de créer des processus pour appliquer la concurrence : + + + +```rust,ignore +{{#include ../../examples/01_02_why_async/src/lib.rs:get_two_sites}} +``` + + + +Cependant, le téléchargement d'une page web est une petite tâche, donc créer un +processus pour une si petite quantité de travail est un peu du gaspillage. Pour +une application plus grosse, cela peut facilement devenir un goulot +d'étranglement. Avec le Rust asynchrone, nous pouvons exécuter ces tâches en +concurrence sans avoir besoin de processus supplémentaires : + + + +```rust,ignore +{{#include ../../examples/01_02_why_async/src/lib.rs:get_two_sites_async}} +``` + + + +Donc ici, il n'y a pas de processus supplémentaires qui sont créés. De plus, +tous les appels à des fonctions sont distribués statiquement, et il n'y a pas +d'allocation sur le tas ! +Cependant, nous avons d'abord besoin d'écrire le code pour être asynchrone, ce +que ce présent libre va vous aider à accomplir. + + + +## Les modèles personnalisés de concurrence en Rust + + + +Sur la dernière remarque, Rust ne vous forçait pas à choisir entre les +processus et l'asynchrone. Vous pouvez utiliser ces deux modèles au sein d'une +même application, ce qui peut être utile lorsque vous mélangez les dépendances +de processus et d'asynchrone. +En fait, vous pouvez même utiliser un modèle de concurrence complètement +différent en même temps, du moment que vous trouvez une bibliothèque qui +l'implémente. diff --git a/FRENCH/src/SUMMARY.md b/FRENCH/src/SUMMARY.md index beeca743..1055588f 100644 --- a/FRENCH/src/SUMMARY.md +++ b/FRENCH/src/SUMMARY.md @@ -1,3 +1,5 @@ # Table des matières + - [Pourquoi l'asynchrone ?](01_getting_started/02_why_async.md) + [Traduction des termes](translation-terms.md) diff --git a/FRENCH/src/translation-terms.md b/FRENCH/src/translation-terms.md index 0917f018..bf2384ce 100644 --- a/FRENCH/src/translation-terms.md +++ b/FRENCH/src/translation-terms.md @@ -5,3 +5,22 @@ français. | Anglais | Français | Remarques | | ------- | ------ | ------ | +| actor model | modèle d'acteur | - | +| callback | fonction de rappel | - | +| CPU | processeur | - | +| concurrent | concurrent | - | +| coroutine | coroutine | - | +| dynamic dispatch | répartition dynamique | - | +| drop | libérer | - | +| flow controle | contrôle de flux | - | +| future | future | - | +| heap | tas | - | +| IO | entrée/sortie | - | +| low-level | bas-niveau | - | +| OS | Système d'Exploitation | Operating System | +| retry logic | logique de relance | - | +| runtime | environnement d'exécution | - | +| state machine | machine à états | - | +| task | tâche | - | +| thread | processus | - | +| thread pool | groupe de processus | - | From 9ad5c4c15b5873257b27af3d9c551406fd79dc5f Mon Sep 17 00:00:00 2001 From: Thomas Ramirez Date: Thu, 3 Feb 2022 22:01:07 +0100 Subject: [PATCH 2/3] Update 02_why_async.md --- FRENCH/src/01_getting_started/02_why_async.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FRENCH/src/01_getting_started/02_why_async.md b/FRENCH/src/01_getting_started/02_why_async.md index b9c491c4..8c1b2760 100644 --- a/FRENCH/src/01_getting_started/02_why_async.md +++ b/FRENCH/src/01_getting_started/02_why_async.md @@ -135,7 +135,7 @@ de Rust de async se distingue des autres langages de plusieurs manières : - Les **futures sont inertes** en Rust et progressent uniquement lorsqu'elles sont sollicitées. Libérer une future va arrêter sa progression. -- **L'asynchrone n'a pas coût** en Rust, ce qui signifie que vous ne payez que +- **L'asynchrone n'a pas de coût** en Rust, ce qui signifie que vous ne payez que ce que vous utilisez. Plus précisément, vous pouvez utiliser async sans allouer sur le tas et sans répartition dynamique, ce qui est très intéressant pour les performances ! From 2ccc68656492a1309ee60b1581d6310ee9325d87 Mon Sep 17 00:00:00 2001 From: Thomas Ramirez Date: Sat, 12 Feb 2022 15:18:57 +0100 Subject: [PATCH 3/3] Self-proofreading of ch01-02 (this is just *wordings* of the translation and not for the *accurancy* of the translation) --- FRENCH/src/01_getting_started/02_why_async.md | 73 +++++++++---------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/FRENCH/src/01_getting_started/02_why_async.md b/FRENCH/src/01_getting_started/02_why_async.md index 8c1b2760..7d13b6df 100644 --- a/FRENCH/src/01_getting_started/02_why_async.md +++ b/FRENCH/src/01_getting_started/02_why_async.md @@ -72,14 +72,14 @@ de la programmation asynchrone : many practical issues unanswered, such as flow control and retry logic. --> -- Les **processus de l'OS** ne nécessitent aucun changement dans le modèle de - programmation, ce qui facilite l'expression de la concurrence. Cependant, la - synchronisation entre les processus peut-être difficile, et la conséquence - sur les performances est importante. Les groupes de processus peuvent réduire - certains coûts, mais pas suffisamment pour faire face à la charge de travail - d'une grosse masse d'entrées-sorties. -- La **programmation orientée évènements**, conjugué avec les _fonctions de - rappel_, peuvent être très performants, mais a tendance à produire un +- Les **processus du système d'exploitation** ne nécessitent aucun changement + dans le modèle de programmation, ce qui facilite l'expression de la + concurrence. Cependant, la synchronisation entre les processus peut être + difficile, et la conséquence sur les performances est importante. Les groupes + de processus peuvent réduire certains coûts, mais pas suffisamment pour faire + face à la charge de travail d'une grosse masse d'entrées/sorties. +- La **programmation orientée évènements**, conjuguée avec les _fonctions de + rappel_, peut s'avérer très performante, mais a tendance à produire un contrôle de flux "non-linéaire" et verbeux. Les flux de données et les propagations d'erreurs sont souvent difficiles à suivre. - Les **coroutines**, comme les processus, ne nécessitent pas de changements @@ -88,7 +88,7 @@ de la programmation asynchrone : font abstraction des détails de bas niveau, qui sont importants pour la programmation système et les implémentations personnalisées d'environnements d'exécution. -- Le **modèle d'acteur** divise tous les calculs concurrents en différentes +- Le **modèle acteur** divise tous les calculs concurrents en différentes parties que l'on appelle acteurs, qui communiquent par le biais de passage de messages faillibles, comme dans les systèmes distribués. Le modèle d'acteur peut être implémenté efficacement, mais il ne répondra pas à tous les @@ -102,7 +102,7 @@ most of the ergonomic benefits of threads and coroutines. En résumé, la programmation asynchrone permet des implémentations très performantes qui sont nécessaires pour des langages bas-niveau comme Rust, tout -en offrant les avantages ergonomiques des processus et des coroutines. +en offrant les avantages ergonomiques aux processus et aux coroutines. -Donc ici, il n'y a pas de processus supplémentaires qui sont créés. De plus, -tous les appels à des fonctions sont distribués statiquement, et il n'y a pas -d'allocation sur le tas ! +Notez bien que ici, il n'y a pas de processus supplémentaires qui sont créés. +De plus, tous les appels à des fonctions sont distribués statiquement, et il +n'y a pas d'allocation sur le tas ! Cependant, nous avons d'abord besoin d'écrire le code pour être asynchrone, ce -que ce présent libre va vous aider à accomplir. +que ce livre va vous aider à accomplir. -Sur la dernière remarque, Rust ne vous forçait pas à choisir entre les +Une dernière remarque, Rust ne vous forçait pas à choisir entre les processus et l'asynchrone. Vous pouvez utiliser ces deux modèles au sein d'une même application, ce qui peut être utile lorsque vous mélangez les dépendances de processus et d'asynchrone.