J'ai une API principale .net qui a un contrôleur qui construit un objet agrégé à renvoyer. l'objet qu'il crée est constitué de données provenant de 3 appels de méthode à une classe de service. Celles-ci sont toutes indépendantes les unes des autres et peuvent être exécutées isolément les unes des autres. Actuellement, j'utilise des tâches pour améliorer les performances de ce contrôleur. la version actuelle ressemble à quelque chose comme ça ...
[HttpGet]
public IActionResult myControllerAction()
{
var data1 = new sometype1();
var data2 = new sometype2();
var data3 = new List<sometype3>();
var t1 = new Task(() => { data1 = service.getdata1(); });
t1.Start();
var t2 = new Task(() => { data2 = service.getdata2(); });
t2.Start();
var t3 = new Task(() => { data3 = service.getdata2(); });
t3.Start();
Task.WaitAll(t1, t2, t3);
var data = new returnObject
{
d1 = data1,
d2 = data2,
d2 = data3
};
return Ok(data);
}
Cela fonctionne bien, mais je me demande si l’utilisation de tâches est la meilleure solution ici? L'utilisation asynchrone/wait serait-elle une meilleure idée et une méthode plus acceptée?
Par exemple, le contrôleur doit-il être marqué comme asynchrone et une attente attendue à chaque appel des méthodes de service?
Cela fonctionne bien, mais je me demande si l’utilisation de tâches est la meilleure solution ici? L'utilisation asynchrone/wait serait-elle une meilleure idée et une méthode plus acceptée?
Oui absolument. Le traitement parallèle sur ASP.NET consomme plusieurs threads par demande, ce qui peut avoir un impact important sur votre évolutivité. Le traitement asynchrone est de loin supérieur pour les E/S.
Pour utiliser async
, commencez par votre appel le plus bas, quelque part dans votre service. Il s'agit probablement d'un appel HTTP à un moment donné; changez-la pour utiliser des appels HTTP asynchrones (par exemple, HttpClient
). Puis laissez async
pousser naturellement à partir de là.
Vous finirez par vous retrouver avec les méthodes asynchrones getdata1Async
, getdata2Async
et getdata3Async
, qui peuvent être consommées simultanément en tant que telles:
[HttpGet]
public async Task<IActionResult> myControllerAction()
{
var t1 = service.getdata1Async();
var t2 = service.getdata2Async();
var t3 = service.getdata3Async();
await Task.WhenAll(t1, t2, t3);
var data = new returnObject
{
d1 = await t1,
d2 = await t2,
d3 = await t3
};
return Ok(data);
}
Avec cette approche, alors que les trois appels de service sont en cours, myControllerAction
utilise zéro threads au lieu de quatre.
[HttpGet]
public async Task<IActionResult> GetAsync()
{
var t1 = Task.Run(() => service.getdata1());
var t2 = Task.Run(() => service.getdata2());
var t3 = Task.Run(() => service.getdata3());
await Task.WhenAll(t1, t2, t3);
var data = new returnObject
{
d1 = t1.Status == TaskStatus.RanToCompletion ? t1.Result : null,
d2 = t2.Status == TaskStatus.RanToCompletion ? t2.Result : null,
d3 = t3.Status == TaskStatus.RanToCompletion ? t3.Result : null
};
return Ok(data);
}
TaskWhenAll
pour renvoyer un objet Task en attente. Ainsi, avec la méthode asynchrone, vous pouvez attendre des tâches au lieu de bloquer le thread.Task<T>
pour renvoyer des résultats du type requis.Task<TResult>.Run
Get
null
pour renvoyer les propriétés de l'objet si certaines tâches ne se terminent pas correctement. Vous pouvez utiliser une autre approche - par exemple renvoyer une erreur si certaines tâches ont échoué.Si j'ai bien compris, vous voulez que cela s'exécute en parallèle, donc je ne pense pas qu'il y a un problème avec votre code. Comme Gabriel l'a mentionné, vous pouvez attendre la fin des tâches.
[HttpGet]
public async Task<IActionResult> myControllerAction()
{
var data1 = new sometype1();
var data2 = new sometype2();
var data3 = new List<sometype3>();
var t1 = Task.Run(() => { data1 = service.getdata1(); });
var t2 = Task.Run(() => { data2 = service.getdata2(); });
var t3 = Task.Run(() => { data3 = service.getdata3(); });
await Task.WhenAll(t1, t2, t3); // otherwise a thread will be blocked here
var data = new returnObject
{
d1 = data1,
d2 = data2,
d2 = data3
};
return Ok(data);
}
Vous pouvez également utiliser les résultats des tâches pour enregistrer certaines lignes de codes et améliorer globalement le code (voir les commentaires):
[HttpGet]
public async Task<IActionResult> myControllerAction()
{
var t1 = Task.Run(() => service.getdata1() );
var t2 = Task.Run(() => service.getdata2() );
var t3 = Task.Run(() => service.getdata3() );
await Task.WhenAll(t1, t2, t3); // otherwise a thread will be blocked here
var data = new returnObject
{
d1 = t1.Result,
d2 = t2.Result,
d2 = t3.Result
};
return Ok(data);
}