Dans le code ci-dessous, à cause de l’interface, la classe LazyBar
doit renvoyer une tâche depuis sa méthode (et pour les arguments, sake ne peut pas être modifié). Si l’ LazyBar
est inhabituelle en ce sens qu’elle s’exécute rapidement et de manière synchrone, quel est le meilleur moyen de renvoyer une tâche sans opération depuis la méthode?
Je suis allé avec Task.Delay(0)
ci-dessous, mais je voudrais savoir si cela a des effets secondaires si la fonction est appelée beaucoup (pour des arguments, disons des centaines de fois par seconde):
Delay(0)
? return Task.Run(() => { });
être différent? Y a-t-il une meilleure façon?
using System.Threading.Tasks; namespace MyAsyncTest { internal interface IFooFace { Task WillBeLongRunningAsyncInTheMajorityOfImplementations(); } /// /// An implementation, that unlike most cases, will not have a long-running /// operation in 'WillBeLongRunningAsyncInTheMajorityOfImplementations' /// internal class LazyBar : IFooFace { #region IFooFace Members public Task WillBeLongRunningAsyncInTheMajorityOfImplementations() { // First, do something really quick var x = 1; // Can't return 'null' here! Does 'Task.Delay(0)' have any performance considerations? // Is it a real no-op, or if I call this a lot, will it adversely affect the // underlying thread-pool? Better way? return Task.Delay(0); // Any different? // return Task.Run(() => { }); // If my task returned something, I would do: // return Task.FromResult(12345); } #endregion } internal class Program { private static void Main(ssortingng[] args) { Test(); } private static async void Test() { IFooFace foo = FactoryCreate(); await foo.WillBeLongRunningAsyncInTheMajorityOfImplementations(); return; } private static IFooFace FactoryCreate() { return new LazyBar(); } } }
L’utilisation de Task.FromResult(0)
ou Task.FromResult
entraînera moins de surcharge que la création d’une Task
avec une expression sans opération. Lors de la création d’une Task
avec un résultat prédéterminé, il n’y a pas de surcharge de planification impliquée.
Aujourd’hui, je vous recommande d’utiliser Task.CompletedTask pour y parvenir.
Pour append à la réponse de Reed Copsey sur l’utilisation de Task.FromResult
, vous pouvez encore améliorer les performances si vous mettez en cache la tâche déjà terminée, car toutes les instances de tâches terminées sont identiques:
public static class TaskExtensions { public static readonly Task CompletedTask = Task.FromResult(false); }
Avec TaskExtensions.CompletedTask
vous pouvez utiliser la même instance dans tout le domaine d’application.
La dernière version de .Net Framework (v4.6) ajoute juste cela à la propriété statique Task.CompletedTask
Task completedTask = Task.CompletedTask;
Task.Delay(0)
tel qu’il était dans la réponse était une bonne approche, car il s’agit d’une copie en cache d’une Task
terminée.
À partir de la version 4.6, Task.CompletedTask
est maintenant plus explicite, mais non seulement Task.Delay(0)
renvoie toujours une seule instance mise en cache, mais renvoie la même instance unique en cache que Task.CompletedTask
.
La nature mise en cache de l’un des deux est garantie de restr constante, mais en tant qu’optimisations dépendantes de l’implémentation et dépendantes de l’implémentation (c’est-à-dire qu’elles fonctionneraient toujours si l’implémentation était encore valide) Task.Delay(0)
était meilleur que la réponse acceptée.
Récemment rencontré ceci et a continué à recevoir des avertissements / erreurs sur la méthode étant annulée.
Nous sums en train d’apaiser le compilateur et cela clarifie les choses:
public async Task MyVoidAsyncMethod() { await Task.CompletedTask; }
Cela rassemble le meilleur de tous les conseils ici jusqu’à présent. Aucune déclaration de retour n’est nécessaire à moins que vous ne fassiez quelque chose dans la méthode.
Je préfère la Task completedTask = Task.CompletedTask;
solution de .Net 4.6, mais une autre approche consiste à marquer la méthode asynchrone et à renvoyer vide:
public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations() { }
Vous obtiendrez un avertissement (CS1998 – Fonction asynchrone sans expression d’attente), mais vous pouvez l’ignorer dans ce contexte.