Présentation des fonctionnalités de développement asynchrone avec .NET et C#

Qu’est-ce qu’une tâche asynchrone

L’un des grands concepts dans le monde du développement avec un grand D est le concept d’exécution synchrone et asynchrone de votre code.

En quelques mots, un code dit asynchrone signifie que son exécution est non bloquante et permet que le flot principal du programme continue de s’exécuter.

Précédemment, j’ai mentionné qu’il s’agissait d’un des grands concept du développement car il sous-entend d’autre concepts reliés à la programmation multithread. Parmi ces concepts, il y a l’attente active (Polling), les fonctions de rappel (callback), Threads et une panoplie d’algorithmes non-bloquants.

Asynchronicité et .NET 4.5

La version 4.5 de .NET apporte deux nouveaux mot clés : async et await.

Ils viennent remplacer la technique qui consistait à invoquer la fonction de démarrage de tâche, exécuter le code en question et déclarer un delegate de retour. Le tout pouvait être assez difficile à suivre dans une majorité de cas.

C’est alors que async et await viennent entrer en jeu lorsqu’il va venir être temps d’avoir des appels asynchrone dans son flux d’exécution. Un exemple typique ressemble à ceci (Tiré de MSDN mais simplifié):

Quelques points intéressants son à noter :

  • La fonction est async car le mot clé est présent dans la signature de celle-ci.
  • Le type de retour est Task<T>.
  • Un appel à une fonction GetStringAsync() avec un type de retour Task<T> est fait.
  • getStringTask est précédé mot clé await avant d’être invoqué.

Le point à retenir dans le scénario présenté est qu’il est facile de concevoir et de comprendre l’ordre d’exécution de celui-ci. Le code va exécuter client.GetStringAsync(« http://msdn.microsoft.com &raquo;) sans, toutefois, attendre son retour avant d’entreprendre l’exécution de GrosseEtLongueTache().

Il est aussi à noter que le type de retour doit être obligatoirement Task<T> avec votre type de retour. Si vous avez une fonction qui retourne rien du tout alors vous devez retourner simplement Task.

API utilisant async

Au moment d’écrire ce billet, il y a une dizaine d’API dans le framework qui exposent des fonctionnalités async. Un drôle de hazard (!) a fait en sorte que ce sont des fonctionnalités où vous devez attendre, dans bien des cas, un peu pour avoir le résultat de l’opération.

Dans le lot, il y a les classes suivantes :

Conclusion

Le bonheur de tout cela est que la conversion de votre code s’exécutant en mode synchrone en mode asynchrone est très simple. Le double avantage réside dans le fait que, dans certains cas, la performance perçue sera augmentée car votre thread principal ne sera pas toujours en attente de vos opérations plus longue à exécuter.

Si vous avez accès à .NET 4.5 et que vous avez accès à ces nouveaux APIs, n’attendez pas que le train passe devant vous et utilisez-les dès maintenant. Vous en ressentirez les effets assez rapidement.

Mes liens de la semaine – #5

Développement

.NET

Web et HTML5

Général

À la découverte du mot clé « yield » avec C# et .NET 4.0

Je me répète lorsque je dis que c’est dans les outils que l’on utilise le plus souvent que l’on ignore le plus les secrets.

Le langage de programmation C# est l’un de mes outils de prédilection. Pour être clair, c’est le langage que j’utilise à tous les jours dans le cadre de mon travail.

Chaque langage a ses spécificités, ses avantages et limitations. En bout de compte, ils nous donnent les moyens de réaliser ce que nous avons à construire.

yield

Jusqu’à récemment, j’avais associé le mot clé yield à Java. Avec Java, le mot clé yield permet de notifier le système que le thread en cours peut être libéré de son exécution pour laisser l’occasion au CPU d’aller exécuter d’autre processus.

Le contexte d’utilisation du mot clé est uniquement réservé au contexte du Threading. Donc, ses utilisations sont très spécifiques et relativement limitées.

Il s’avère qu’avec .NET, le mot clé yield est associé aux collections et non pas au threading. Ceci étant dit, il n’est pas évident d’en deviner son utilisation à moins de lire la définition de celui-ci dans MSDN.

The yield keyword, indicates that the method, operator, or get accessor in which it appears is an iterator. You use an iterator to perform a custom iteration over a collection. The following example shows the two forms of the yield statement.

yield return <expression>;
yield break;

En autre termes, yield permet indique que vous pourrez itérer sur ce que vous retournerez au moment où vous l’utiliserez.

Pratiquement parlant, son utilisation et surtout reliée au cas où vous désirez extraire d’une collection un certain nombre de sous éléments. Par exemple, filtrer une liste d’utilisateurs par leur âge et procéder à un traitement spécifique pour un certain regroupement.

Utilisation

Utiliser yield implique très peu de choses à la structure de son code. Il faut toutefois changer l’approche avec laquelle on utilise ses collections.

Le meilleur exemple est assez visuel. Il est possible de procéder au calcul de la suite de Fibonacci de façon assez élégante de cette façon.

L’élégance vient du fait que cette fonction peut être utilisée dans une boucle ForEach comme ceci :

Avec yield, il n’est pas question de réécrire fanatiquement ses fonctions manipulant des collections en tenant compte que le mot clé est à notre disposition. Bien au contraire!

Toutefois, je crois qu’il est important de savoir comment fonctionne le Framework lorsqu’il est temps de manipuler des listes d’éléments. D’ailleurs, est-ce qu’il est nécessaire de mentionner que LINQ utilise déjà cette approche?

Ressources supplémentaires

Expérimentation avec System.Tuple – Du code sans DTO conventionnels?

Par définition, un DTO (Data Transfer Object) permet l’échange de données à travers différentes couche logicielles d’une application. À titre d’exemple, un DTO permet de représenter par une structure de données l’information qui va provenir de votre base de données. L’utilisation est au coeur même du principe qui permet d’écrire du code réutilisable et facilement maintenable.

Tuple, c’est quoi ça?

Un Tuple ou même n-uplet en français est une structure de données permettant de regrouper des types hétérogènes ensemble. Pour ceux plus familier avec l’aspect mathématique de la chose, un Tuple est le concept de Couple étendu à N types.

Avec .NET, il y a huit variations de la classe Tuple. Chacune des variations a son nom qui la distingue :

  • Tuple<T1> : Singleton
  • Tuple<T1, T2> : Couple
  • Tuple<T1, T2, T3> : Triplet
  • Tuple<T1, T2, T3, T4> : Quadruplet
  • Tuple<T1, T2, T3, T4, T5> : Quintuplet
  • Tuple<T1, T2, T3, T4, T5, T6> : Sextuplet
  • Tuple<T1, T2, T3, T4, T5, T6, T7> : Heptuplet
  • Tuple<T1, T2, T3, T4, T5, T6, T7, T8> : Octuplet
Il est possible de créer un Tuplet considéré comme infini ayant la signature Tuple<T1, T2,T3, T4, T5, T6, T7, TRest>. Il est considéré infini car le dernier type TRest peut être utilisé pour imbriquer d’autres Tuplets. Il n’y a pas de limite théorique au nombre de Tuplets qui peuvent être imbriqués.
Un Tuple ayant la signature Tuple<string, string, string, int, Image> peut se créer de la façon suivante, par exemple :

Le concept proposé

Mon but initial lorsque j’ai lu à propos de Tuple serait de savoir s’il serait réellement pratique de l’utiliser avec ExpandoObject pour transporter un certain nombre de données.

Avec la venue de la classe ExpandoObject dans .NET4, il est possible d’ajouter dynamiquement des propriétés à un objet. L’idée m’est venue de tenter de combiner, le temps d’un essai, de combiner ExpandoObject et Tuple ensemble.

Le concept que j’ai développé est disponible pour consultation sur GitHub. Il y a deux méthodes qui sont à regarder : TupleExemple.(Tuple<string, string, string, int, Image> user) et UserRepository.GetRegisteredUserList(). De plus, l’appel à ces deux méthodes est fait dans le constructeur de TupleExemple.

Le constat

Initialement, lorsque j’ai pondu ce code, j’ai été sur l’impression d’avoir trouvé une nouvelle façon d’écrire du code. Mon impression était, qu’avec un nombre limité de propriétés à transporter, un Tuple serait un excellent moyen de transport. Le seul facteur qui me permettait d’affirmer cela est que, dans ce cas-ci, je n’aurais pas à eu besoin de recourir à une classe servant de DTO.

Après relecture de ParseUserInformations, je crois qu’il faut utiliser beaucoup de jugement lorsqu’il est temps d’utiliser un Tuple pour exposer une structure de données qui sera au cœur de votre application. Sur 50 lignes de code, il est facile de se souvenir qu’Item3 est relié au courriel. Toutefois, qu’en sera-t-il lorsque vous tenterez de le faire la même chose avec 10 000 lignes de code?

À mon avis, un scénario idéal pour utiliser Tuple, serait dans le cadre d’opérations très ciblés ayant un contexte précis. Ce que j’ai souvent en tête, c’est une classe en charge de l’importation d’une liste d’utilisateurs dans votre base de données.

Le but serait d’avoir, au sein de la même classe ou méthode, tout ce qu’il faut pour récupérer la source de données originale. Soit la représenter avec un Tuple, faire les transformations nécessaires et l’importer dans votre base de données.

Un hommage à String.IsNullOrEmpty()

Il faut du recul pour se donner de la perspective sur le chemin qui a été parcouru dans les dernières années. En tant que développeur, il est force d’admettre que les choses évoluent dramatiquement rapidement.

Du côté de .NET, vous vous souvenez de l’époque de .NET 1.1? Comparé à ce qui est possible de faire aujourd’hui, il est à se demander comment il était même possible d’arriver à développer avec ce Framework là!

De mémoire, vous vous souvenez ce qui vous a marqué le plus avec la version 2.0 de .NET? Est-ce que ce serait l’un des points suivants ?

Providers

  • Membership
  • Role
  • Sitemap
  • Profile
  • Session
  • Web events
  • Web Parts

ASP.NET Code behind

/app_code ?

Generics?

ASP.NET Thèmes et skins ou même les Master Pages ?

Classes partielles

Itérateurs?

Non!

Pour moi, l’amélioration la plus marquante a été String.IsNullOrEmpty() aura été celle que j’utilise le plus dans tout le Framework. Elle fait, dans une très grande majorité de cas, partie de la première validation sur l’état d’une string lorsqu’on la reçoit en paramètre.

Son implémentation est très simple. Par son nom, il est très facile de déterminer son but : Est-ce que cette chaîne de caractères est de type null ou vide?

Sommairement, cette fonction permet de convertir le code suivant :

var isValid = (maString== null || maString.Length == 0);

de cette façon :

var isValid =  (string.IsNullOrEmpty(maString));

Un hommage

À la blague, j’ai même démarré avec la collaboration d’un ami un micro-blogue en hommage à String.IsNullOrEmpty(). Un billet que j’aime particulièrement est l‘internationalisation de String.IsNullOrEmpty(). L’article met en lumière qu’il n’est quand même pas si simple d’écrire cette même validation en Javascript.

La validation poussée à son maximum

Lorsque j’ai eu à chercher des idées pour ce billet, j’ai trouvé le gist suivant sur Github (note : ne pas faire lire aux enfants) :

Élégant, clair, très expressif et surtout vulgaire. Adorable! Pourquoi faire simple lorsqu’on peut littéralement inclure la totalité des validations de String dans la même fonction?

Conclusion

Je vais l’avouer, mon affection envers String.IsNullOrEmpty est légèrement démesurée.

Toutefois, à quand revient le dernier moment où vous avez écrit une validation pour déterminer si votre String était null ou vide à l’ancienne? Probablement que ça date de l’instant où vous avez découvert que la fonction existait.

Si vous êtes arrivés sur le billet et que vous venez d’apprendre l’existence même de cette fonction, je crois alors que ma mission de prêcher la bonne nouvelle aura été accomplie!