est-il inefficace puisque vous êtes essentiellement la création d'un nouveau thread pour chaque couche (de manière asynchrone à l'appel d'une fonction asynchrone pour chaque couche, ou n'est-il pas vraiment d'importance et il est juste en fonction de votre préférence?
Pas de. Méthodes asynchrones ne sont pas nécessairement utiliser de nouveaux threads. Dans ce cas, puisque le sous-jacent appel de méthode asynchrone est un IO lié méthode, il faudrait vraiment pas de nouveaux threads créés.
Est-ce:
1. necessary
Il est nécessaire de "bulle" les appels asynchrones si vous souhaitez conserver l'opération asynchrone. C'est vraiment préféré, cependant, car il vous permet de profiter pleinement de toutes les méthodes asynchrones, y compris la composition de leur ensemble à travers l'ensemble de la pile.
2. negative on performance
Pas de. Comme je l'ai mentionné, ce n'est pas de créer de nouveaux threads. Il y a une surcharge, mais beaucoup de ce qui peut être réduite (voir ci-dessous).
3. just a matter of preference
Pas si vous voulez garder cette asynchrone. Vous avez besoin de faire garder les choses asynchrone dans la pile.
Maintenant, il ya certaines choses que vous pouvez faire pour améliorer les perf. ici. Si vous êtes juste envelopper une méthode asynchrone, vous n'avez pas besoin d'utiliser les fonctionnalités de la langue - il suffit de retourner l' Task
:
public virtual Task Save()
{
return repository.Save();
}
L' repository.Save()
méthode retourne déjà un Task
- vous n'avez pas besoin d'attendre juste pour l'envelopper de retour dans un Task
. Cela permet de garder la méthode un peu plus efficace.
Vous pouvez aussi avoir votre "bas niveau" des méthodes asynchrones utiliser ConfigureAwait
pour les empêcher d'avoir besoin de l'appeler contexte de synchronisation:
private async Task<string> Dosomething2()
{
//other stuff
...
return await Dosomething3().ConfigureAwait(false);
}
Cela réduit considérablement les coûts de chaque await
si vous n'avez pas besoin de s'inquiéter sur le contexte de l'appel. Ce est généralement la meilleure option lorsque vous travaillez sur la "bibliothèque" du code, depuis "l'extérieur" await
la capture à l'INTERFACE utilisateur du contexte. Le "intérieure" fonctionnement de la bibliothèque n'a généralement pas de soins sur la synchronisation contexte, il est donc préférable de ne pas capturer.
Enfin, je l'avais mise en garde contre l'un de vos exemples:
private async Task<string> Dosomething3()
{
//other stuff
...
// Potentially a bad idea!
return await Task.Run(() => "");
}
Si vous effectuez une méthode async qui, en interne, est à l'aide de Task.Run
de "créer de l'asynchronie" autour de quelque chose qui n'est pas lui-même asynchrone, vous êtes effectivement emballage synchrone code dans une méthode asynchrone. Ce sera l'utilisation d'un pool de threads thread, mais peut "cacher" le fait qu'il est le faire, ce qui fait de l'API trompeuse. Il est souvent préférable de laisser l'appel à Task.Run
pour votre plus haut niveau des appels, et de laisser le sous-jacent méthodes rester synchrone sauf si elles sont vraiment en mesure de profiter de l'asynchrone IO ou certains moyens de déchargement autre que Task.Run
. (Ce n'est pas toujours vrai, mais "async" code enveloppé sur code synchrone via Task.Run
, alors retourné par async/await est souvent le signe d'un défaut de conception.)