En termes de performances, ces 2 méthodes exécuteront-elles GetAllWidgets()
et GetAllFoos()
en parallèle?
Y at-il une raison pour utiliser l'un sur l'autre? Il semble y avoir beaucoup de choses qui se passent dans les coulisses avec le compilateur, donc je ne trouve pas cela clair.
============= MéthodeA: L'utilisation de plusieurs attend ======================
public async Task<IHttpActionResult> MethodA()
{
var customer = new Customer();
customer.Widgets = await _widgetService.GetAllWidgets();
customer.Foos = await _fooService.GetAllFoos();
return Ok(customer);
}
=============== MethodB: Utilisation de Task.WaitAll ====================
public async Task<IHttpActionResult> MethodB()
{
var customer = new Customer();
var getAllWidgetsTask = _widgetService.GetAllWidgets();
var getAllFoosTask = _fooService.GetAllFos();
Task.WaitAll(new List[] {getAllWidgetsTask, getAllFoosTask});
customer.Widgets = getAllWidgetsTask.Result;
customer.Foos = getAllFoosTask.Result;
return Ok(customer);
}
=====================================
La première option n'exécutera pas les deux opérations simultanément. Il exécutera le premier et attendra son achèvement, puis seulement le second.
La deuxième option s’exécutera simultanément mais les attendra de manière synchrone (c’est-à-dire en bloquant un thread).
Vous ne devez pas utiliser les deux options car la première se termine plus lentement que la seconde et la seconde bloque un thread sans nécessité.
Vous devez attendre les deux opérations de manière asynchrone avec Task.WhenAll
:
public async Task<IHttpActionResult> MethodB()
{
var customer = new Customer();
var getAllWidgetsTask = _widgetService.GetAllWidgets();
var getAllFoosTask = _fooService.GetAllFos();
await Task.WhenAll(getAllWidgetsTask, getAllFoosTask);
customer.Widgets = await getAllWidgetsTask;
customer.Foos = await getAllFoosTask;
return Ok(customer);
}
Notez qu'après la fin de Task.WhenAll
, les deux tâches déjà terminées sont donc terminées immédiatement.
Réponse courte: non.
Task.WaitAll
bloque, await
renvoie la tâche dès qu'elle est rencontrée et enregistre la partie restante de la fonction et sa suite.
La méthode d'attente "en bloc" que vous recherchiez est Task.WhenAll
, ce qui crée une nouvelle variable Task
qui se termine lorsque toutes les tâches confiées à la fonction sont terminées.
Comme si: await Task.WhenAll({getAllWidgetsTask, getAllFoosTask});
C'est pour le blocage.
De plus, votre première fonction n'exécute pas les deux fonctions en parallèle. Pour que cela fonctionne avec await
, vous devez écrire quelque chose comme ceci:
var widgetsTask = _widgetService.GetAllWidgets();
var foosTask = _fooService.GetAllWidgets();
customer.Widgets = await widgetsTask;
customer.Foos = await foosTask;
Cela rendra le premier exemple très similaire à la méthode Task.WhenAll
.
Seule votre deuxième option les exécutera en parallèle. Votre premier attendra chaque appel en séquence.
Dès que vous appelez la méthode asynchrone, son exécution commence. Il n'est pas possible de déterminer s'il sera exécuté sur le thread actuel (et donc exécuté de manière synchrone) ou asynchrone.
Ainsi, dans votre premier exemple, la première méthode commencera à fonctionner, mais vous arrêterez alors artificiellement le flux du code avec l'attente. Et ainsi, la seconde méthode ne sera pas invoquée avant que la première ne soit exécutée.
Le deuxième exemple appelle les deux méthodes sans arrêter le flux avec une attente. Ainsi, ils s'exécuteront potentiellement en parallèle si les méthodes sont asynchrones.