La programmation asynchrone revisitée avec async/await

La programmation asynchrone a toujours été un sujet délicat, abordé avec plus ou moins de bonheur selon les développeurs et leur expérience. Pourtant, ce concept est au cœur de bien des problématiques, que l’on travaille dans un environnement applicatif ou web.

La principale difficulté réside dans le fait que le code asynchrone ne s’écrit pas (et à fortiori ne se lit pas) de façon séquentielle, une ligne après l’autre, suivant la logique imposée par notre apprentissage scolaire de la lecture.

En règle générale, une exécution asynchrone est résolue en C# par l’inscription d’un handler à l’évènement « End[nomDeLaMéthodeAsynchrone] » suivi d’un appel à la méthode « Begin[nomDeLaMéthodeAsynchrone] » laquelle, lorsqu’elle aura terminé son travail, aura le bon goût de lever l’évènement suscité. Avec un peu de chance, le handler est une méthode au nom explicite dont l’implémentation est disponible quelques lignes plus bas. Dans le pire des cas, un amateur chevronné des expressions lambda aura pondu une implémentation « inline » de quelques centaines de lignes, reproduisant récursivement le schéma « inscription du handler=>appel du begin ». Le résultat, en plus d’avoir procuré une migraine bien méritée à son auteur, aura de quoi rendre perplexe plus d’une victime à qui on aura confié la maintenance du code en question. Un simple passage au débugger aura tôt fait d’illustrer à quel point le flux d’exécution d’un tel code peut être déroutant.

Avec l’arrivée de Windows 8 et de son API WinRT qui ajoute à .NET 4.5 son lot de méthodes asynchrones, Microsoft a jugé utile de simplifier cette problématique complexe, même lorsqu’elle est bien traitée, en fournissant avec le compilateur C# de Visual Studio 2012 deux nouveaux mots clefs: « await » et « async ». La documentation officielle sur le sujet décrit de manière claire et concise le fonctionnement de ces mots clefs et il n’est pas question ici d’en refaire la démonstration.

En guise d’amuse-bouche, disons simplement que le mot clef « async » définit qu’une méthode est asynchrone, et que le mot clef « await » précédant l’appel d’une telle méthode indique au compilateur que son appel doit être réalisé de manière asynchrone. Lorsque ce dernier trouve le mot clef « await » au milieu de votre code, il va automatiquement découper celui-ci en deux, et encapsuler les lignes suivant le « await » (ainsi que leur contexte de variables locales) dans un handler qu’il inscrira pour vous à l’évènement de fin d’exécution de la méthode asynchrone.

Comme beaucoup d’instructions « magiques » du langage C# (je pense par exemple au « yield return », qui mérite son propre billet), certains réfractaires pourront argumenter que déléguer au compilateur la complexité d’implémentation retire au développeur la maîtrise de son code; mais il faut bien admettre que c’est vachement pratique de pouvoir écrire (et lire) du code comme s’il était synchrone, tout en sachant que son exécution tiendra compte des contraintes imposées par l’API sous-jacente.

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

treize − trois =