Pourquoi faire de l’asynchronisme ? Tout simplement pour éviter de bloquer un thread. En effet si votre application graphique fait appel à un traitement long (I/O, CPU, réseau…) directement dans le thread graphique, ce dernier sera bloqué le temps de l’exécution et votre utilisateur se retrouvera avec une application bloquée.

Evidemment il est tout à fait possible de contourner ce problème sans le Async/Await, et heureusement que nous n’avons pas attendu le Framework 4.5 pour cela !

Prenons pour exemple une application graphique avec un bouton et un label, lorsque l’on clique sur le bouton, on appelle une méthode très complexe qui va occuper note CPU pendant au moins deux secondes; si vous ne comprenez pas l’algorithme ce n’est pas gênant pour la suite 😉

private void button1_Click(object sender, EventArgs e)
{
 Hello(“world”);
}

private void Hello(string name)
{
 Thread.Sleep(2000); //super algorithme!!!
 label1.Text = string.Format("Hello {0}!!!",name);
}

Première solution : le multithreading

C’est la solution la plus couramment utilisée, en effet nous allons exécuter notre code bloquant dans un nouveau thread, c’est un peu la bonne poire : « tu ne veux pas attendre à ma place ? »

private void button1_Click(object sender, EventArgs e)
{
 label1.Text="working...";
 new Thread(() => {
 Hello("world");
 }).Start();
}

Malheureusement cela ne fonctionne pas tel quel :

cross thread exception

Erreur classique : on essaye d’accéder à une ressource qui se trouve dans un thread différent désormais…

Pour résoudre cela vous avez besoin du SynchronizationContext du thread UI, après correction cela donne :


private void button1_Click(object sender, EventArgs e)
{
SynchronizationContext uiContext = SynchronizationContext.Current;
new Thread(() =>
{
uiContext.Post(Hello,"world");
}).Start();
label1.Text = "working...\n";
}

private void Hello(object state)
{
Thread.Sleep(2000); //super algorithme!!!
label1.Text = string.Format("Hello {0}!!!",state as string);
}

Deuxième solution : Async/Await

Maintenant que l’on a vu le peu de trivialité à utiliser plusieurs thread la solution suivante va vous sembler déconcertante de simplicité :


private async void button1_Click(object sender, EventArgs e)
{
label1.Text = "working...\n";
await HelloAsync("world");
}

private async Task HelloAsync(string name)
{
await Task.Delay(2000); //super algorithme 2!!!
label1.Text = string.Format("Hello {0}!!!",name);
}

Comme vous pouvez le constater les changements sont minimes et la syntaxe est très proche du mode synchrone, d’ailleurs le debugger de VS2012 permet de faire du pas à pas comme si vous étiez en mode synchrone. A la différence du multithreading, nous n’utilisons bien qu’un seul thread ici, le thread UI :

Async Thread

Par convention, suffixez toujours le nom de votre méthode asynchrone par « Async ». Vous retrouverez cette convention dans le Framework lui-même.

Pour pouvoir utiliser « await » vous devez ajouter « async » à votre signature.

Je vous ai illustré un cas simple d’utilisation, dans un prochain post nous verrons comment récupérer des informations sur l’exécution de notre méthode asynchrone, les différents pièges possibles et nous irons voir ce qui se passe sous le capot 😉