Bonjour,
Je me demande quelle était la différence entre utiliser les mots clés Async/await ou juste le multithreading que l'on utilise déjà depuis quelques temps maintenant ?
Bonjour,
Je me demande quelle était la différence entre utiliser les mots clés Async/await ou juste le multithreading que l'on utilise déjà depuis quelques temps maintenant ?
async/await n'est rien d'autre qu'une sur-couche au dessus de la TPL (elle même une surcouche des outils de multi-threading .Net) qui permet de "linéariser" l'écriture de code asynchrone, là où les continuations introduites avec la TPL pouvaient s'imbriquer sur n niveaux rendant la compréhension du code plus difficile.
Le principe est directement repris de Node.js et d'autres projets similaires et c'est donc surtout pertinent pour les traitements I/O-bound.
Les équipes de Microsoft ont fait un gros travail d'intégration pour que l'utilisation soit relativement transparente depuis C# notamment.
Donc si tu as de l'existant utilisant la TPL, le pool, ou directement des threads, inutile de tout casser pour passer à async/await.
En revanche pour le nouveau code tu peux te poser la question au cas par cas.
Merci pour ta réponse très détaillée .
Je pars de zéro donc effectivement je me pose la question. D'ailleurs, j'ai lu que Async/Await ne créait pas de thread, donc du coup, quid de la parallélisation et de l'avantage des threads d'être découpés sur divers coeurs de processeur ? (on est dans la perf pure mais vu les traitements que j'ai à réaliser cette question est pertinente )
async/await encapsule une infrastructure plus complexe qui peut en effet ne pas créer de thread, typiquement dans le cadre des interfaces graphiques (WinForms, WPF, WinRT...).
Mais async/await n'est pas vraiment un outil de parallélisation, plutôt d'asynchronie, pour éviter de monopoliser des threads pour l'attente I/O.
Concernant la parallélisation, je préconise (dans la mesure du possible) d'utiliser l'API .NET Parallel.XXXX (Parallel.For, Parallel.ForEach, ...)
Mais attention de paralléliser n'est pas forcement gagnant à tous les coups. Le fait de paralléliser à un coup (synchronisation des threads, appel de la fonction delegate, ..)
J'utilise assez souvent le parallélisme des boucles For et effectivement la courbe des performances est loin d'être linéaire. Quand je parlais de parallélisation, je parlais plutôt de l'affectation des threads à un coeur de processeur différent (ex: un thread traitement d'image sur un coeur, un thread GUI sur un autre coeur et un thread connectivité sur une autre coeur). Ce genre de parallélisation est implicite et est géré par l'OS.
Si je découpe mon code avec plusieurs méthodes méthodes asynchrones Async/Await, celles-ci seront elles "parallélisées" implicitement par l'OS de la même manière qu'avec les threads ?
Le propos n'a pas de sens, tu as mal compris le rôle d'async/await. Async/await ne distribue pas les tâches, ce sont simplement des moyens commodes de les enchaîner pour linéariser l'écriture.
* Utiliser await ne démarre pas une opération, c'est le rôle de l'expression derrière await. Await ne fait que connecter la tâche renvoyée par cette expression au point d'exécution courant. Quant cette sous-tâche sera terminé, le travail reprendra à partir du point d'exécution actuel et, par défaut, sur le contexte de synchronisation actuel (le thread UI par exemple).
* Utiliser async n'a aucun impact sur l'exécution de la fonction elle-même. Cette fonction s'exécutera de façon synchrone comme n'importe quelle fonction jusqu'au moment où elle rencontrera un await (elle se terminera alors). Là encore c'est donc l'expression derrière await qui crée le parallélisme (ou non).
L'expression derrière await peut donc choisir de créer un thread, de balancer sur la thread poo, etc. C'est à elle et à elle seule de décider quoi faire. Par exemple Task.Run ou Parallel.xxx balanceront des travaux sur le ThreadPool, lequel crée des threads au besoin et les réutilise ensuite pour les futurs travaux.
En revanche j'insiste sur le fait qu'une fois la sous-tâche terminée le travail reprend par défaut sur le contexte de synchronisation d'origine. Le thread UI est un exemple de contexte de synchronisation : toute opération démarrée sur celui-ci reprendra par défaut sur celui-ci après le await. Un autre exemple est le contexte du ThreadPool : toute opération démarrée sur un thread du ThreadPool reprendra par défaut sur un thread du ThreadPool, mais pas forcément le même puisqu'ils forment ensemble un seul contexte.
Si tu n'as pas compris, demande-moi et je te donnerai un exemple de la façon dont async/await sont traduits.
Bonjour Donquiche,
Pour être sûr, je veux bien si possible que tu me donne un exemple .Si tu n'as pas compris, demande-moi et je te donnerai un exemple de la façon dont async/await sont traduits.
Ok, alors considérons par exemple le code suivant :
Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 async Task DaFunc(int x) { Start(); await SomeAsyncStuff(); Conclude(x); }
Est compilé en tant que :
Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 Task DaFunc(x) { Start(); return SomeAsyncStuff().ContinueWith(() => Conclude(x), TaskScheduler.FromCurrentSynchronizationContext); }
Si SomeAsyncStuff() lance une opération asynchrone, alors la fonction DaFunc va tout de suite se terminer sans attendre la fin de l'opération. En revanche quand celle-ci sera terminée le contenu de ContinueWith sera exécuté sur le thread UI (le contexte de synchronisation courant quand DaFunc fut exécuté).
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager