Programmation asynchrone et barre de progression

Le Framework .NET 4.5 a apporté une nouveauté assez géniale : await/async.

Cette nouveauté permet de manipuler les tâches asynchrone d’une manière facilitée, et surtout sécurisée.
Facilité parce qu’il suffit de ne retenir que trois mots Task, async, await.
Sécurisé car il est presque impossible d’avoir un deadlock quand on utilise les décorateurs async/await alors qu’on fait du multithread.

Le code de base est celui-ci :

Il est absoluement nécessaire d’avoir dans votre fonction un await quelque part.
L’effet de await est globalement de lancer la tâche, attendre qu’elle finisse, prendre son résultat et le retourner sans se soucier de l’encapsulation sous forme de Task.
L’avantage principal, c’est que le temps qu’il passe à attendre… il n’utilise pas de ressource processeur.
Ce qui peut s’avérer une très bonne chose si votre tâche demande beaucoup d’attente (communication avec une BDD, un service web…)

A noter, on peut aussi mettre un async sur une fonction de type void. C’est déconseillé sauf sans un cas : quand vous désirez rendre asynchrone un écouteur d’événement pour vos interfaces utilisateurs.
Si vous faites du développement windows phone, presque tout ce qui demande des entrées/sorties doit passer par des fonctions asynchrones.

Un autre aspect que je voulais évoquer avant de passer à la partie “barre de progression”, c’est la parallélisation des tâches.
Pendant que votre tâche est mise en attente, votre processeur peut faire autre chose, de plus comme il a sûrement plusieurs coeurs, il peut exécuter plusieurs tâches simultanément.
Et c’est là que la parallélisation arrive.
Comme je vous l’ai dit, await/async vous promettent une absence de deadlock donc mangez-en!
A noter aussi que TOUTES les collections du framework .NET version 4.5 sont threadsafe, ce qui signifie que si vos tâches parallèles partagent une ressource tout sera synchroniser comme il le faut pour le peu que vous utilisiez lock dans votre tâche.

Mais comment parallélise-t-on?
Une manière simple de voir les choses, c’est de dire :
Je liste tout ce que je dois faire, et je lance et j’attends que tout soit fait.
Quand on code, ça donne :

 
Il existe quelques bonnes pratiques pour faire de l’asynchrone, mais vous avez vu le principal.

Maintenant, voyons la problématique des barre d’avancement/de progression.
Je travaille ici en WindowsForm, mais en WPF, vous avez aussi un objet ProgressBar et ce dernier aura les mêmes limites que ce que je vais vous présenter maintenant.

Quand on travaille sur l’interface utilisateur, chaque formulaire, ou présentation de base tourne dans un thread et c’est uniquement au sein de ce thread que les contrôles de l’interface peuvent être modifiés (comme l’ajout d’objet dans une combobox).
La ProgressBar n’y échappe pas.
Ma problématique était celle-ci :
je devais lancer l’enregistrement (qui demande quelques traitements de validation, de création de liens…) d’une dizaine d’entités à travers un webservice.
Le plus difficile était de créer les liens dont je vous parler tant et si bien que je me retrouvais avec le besoin d’afficher une barre de progression de l’enregistrement qui s’incrémentait dès qu’une entité était enregistrée.
Ma première idée avait été de “paralléliser” comme je vous l’ai montré juste avant.
Je créais une tâche qui retournait vrai ou faux selon la réussite de la tâche puis je demandais à ma barre de progression d’avancer.
Elle ne le faisait jamais.

 
Une autre idée a ensuite été de lancer les tâches sans la progressBar1.performStep() mais de le mettre seulement une fois qu’une tâche, peu importe laquelle avait réussi.

 
Une nouvelle fois, ça ne fonctionnait pas. En effet, le await bloquait le thread trop vite du coup le performStep() ne faisait rien.

Pour en arriver à mes fins, j’ai du voyager sur stackoverflow afin de trouver un nouveau jouer pour faire de l’asynchrone : BackgroundWorker.
Ce dernier est asynchrone et se sert d’événements pour tout faire fonctionner. Mais surtout, il possède une notion de progression de la tâche. En somme, ce que nous, nous voulons faire.
Voici comment ça marche :

 

Leave a Reply

Your email address will not be published. Required fields are marked *