Petit aperçu sur les tâches asynchrones avec C# 5.0

L’asynchronisme illustre le fait d’éxecuter plusieurs tâches en parallèle, sans ordonnancement ni interblocage.

L’exemple le plus couramment rencontré est celui du téléchargement de fichier : durant le processus de téléchargement, l’utilisateur peut en parallele, naviguer sur son system et lancer d’autres tâche.

Dans le cadre de ce billet, nous allons simuler 3 tâches asynchrones entre elles (monitoring de server, envoie d’e-mail, téléchargement de fichier).

Ensuite nous allons découvrir différentes méthode afin de contrôler l’exécution séquentielle de ces 3 tâches (les unes à la suite des autres) comme s’il s’agissait d’opérations synchrone.

 

private static int TestChoice()
{
	Console.WriteLine("Type test 1,2,3 or 4: ");

	int testId = Convert.ToInt32(Console.ReadLine());

	return testId;
}

En fonction du choix de l’utilisateur (1,2,3 ou 4) la méthode asynchrone simulant nos 3 tâches (monitoring, e-mail, téléchargement) est appelé.

private static async void Run(int testID)
{
	switch(testID) 
	{
		case 1:
			await RunIt();
			break;
		case 2:
			await RunItFaster();
			break;
		case 3:
			await RunItEvenFasterV1();
			break;
		case 4:
			await RunItEvenFasterV2();
			break;
	}
}

Le prefixe await signifie que le programme doit attendre la fin de la méthode asynchrone appelé avant de poursuivre.

Si on utilise await dans une fonction, alors celle-ci doit être déclaré async.

private static async Task<string> RunIt()
{
    var start = DateTime.Now;

    Console.WriteLine("[{0}] START ", start);
    
    var tasktorun = new TasksToRun();

    await tasktorun.MonitorServer(2000);
    await tasktorun.SendMail(2000);
    await tasktorun.DownloadFile(2000);

    var end = DateTime.Now;

    Console.WriteLine("[{0}] END ", end);
    Console.WriteLine("Elapsed time : {0} ", end - start);

    return "Done";
}

Dans le cas suivant, inutile de préfixer avec await la tâche de monitoring. En effet monitoring n’est pas déclaré asynchrone (cf class TasksToRun).

En conséquence, le monitoring s’execute en même temps que l’envoi de mail. Une fois l’envoi de mail terminé alors le téléchargement s’exécute.

Cela explique la réduction du temps d’exécution des 3 tâches.

private static async Task<string> RunItFaster()
{
	var start = DateTime.Now;

	Console.WriteLine("[{0}] START ", start);

	var tasktorun = new TasksToRun();

	tasktorun.MonitorServer(2000);

	await tasktorun.SendMail(2000);
	await tasktorun.DownloadFile(2000);

	var end = DateTime.Now;

	Console.WriteLine("[{0}] END ", end);
	Console.WriteLine("Elapsed time : {0} ", end - start);

	return "Done";
}

Ci-dessous la méthode static whenAll() est prefixé avec le mot-clé await: on lance les 3 opérations en même temps.

Peu importe dans quel ordres celles-ci s’executent, et se terminent.

Une fois les 3 tâches executées, on passe à la suite du programme.

private static async Task<string> RunItEvenFasterV1()
{
	var start = DateTime.Now;

	Console.WriteLine("[{0}] START ", start);

	var tasktorun = new TasksToRun();

	var monitorServer = tasktorun.MonitorServer(2000);
	var emailToSend = tasktorun.SendMail(2000);
	var randomInt =  tasktorun.DownloadFile(2000);

	await Task.WhenAll(monitorServer, emailToSend, randomInt);

	var end = DateTime.Now;

	Console.WriteLine("[{0}] END ", end);
	Console.WriteLine("Elapsed time : {0} ", end - start);

	return "Done";
}

Autre manière de procéder à l’execution coordonnées des 3 tâches en utilisant la class Func<>

private static async Task<string> RunItEvenFasterV2()
{
	var start = DateTime.Now;

	Func<int, Task<string>> target = null;

	Console.WriteLine("[{0}] START ", start);

	var tasktorun = new TasksToRun();

	target = tasktorun.MonitorServer;
	target += tasktorun.SendMail;
	target += tasktorun.DownloadFile;

	await Task.WhenAll(target(2000));

	var end = DateTime.Now;

	Console.WriteLine("[{0}] END ", end);
	Console.WriteLine("Elapsed time : {0} ", end - start);

	return "Done";
}

Définition de la classe qui simule les 3 opérations de monitoring, e-mail, et téléchargement avec une temps d’exécution de 2sec chacune.

public class TasksToRun
{
	public Task<string> MonitorServer(int ms)
	{
		Console.WriteLine("Enter MonitorServer()");

		return Task.Delay(ms).ContinueWith(_=&amp;amp;gt;"Leave MonitorServer");
		
	}

	public async Task<string> SendMail(int ms)
	{
		Console.WriteLine("Enter SendMail()");

		return await Task.Delay(ms).ContinueWith(_ =&amp;amp;gt; "Leave SendMail");
	}

	public async Task<string> DownloadFile(int ms)
	{
		Console.WriteLine("Enter DownloadFile()");

		return await Task.Delay(ms).ContinueWith(_ =&amp;amp;gt; "Leave DownloadFile");
	}
}

Leave a Reply

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