Im folgenden Code muss die Klasse LazyBar
aufgrund der Schnittstelle eine Aufgabe von ihrer Methode zurückgeben (und aus Gründen der Argumentation kann sie nicht geändert werden). Wenn die Implementierung von LazyBar
insofern ungewöhnlich ist, als sie schnell und synchron ausgeführt wird - wie kann eine No-Operation-Task am besten von der Methode zurückgegeben werden?
Ich bin mit Task.Delay(0)
weiter unten gegangen, möchte jedoch wissen, ob dies irgendwelche Leistungsnebenwirkungen hat, wenn die Funktion lot (aus Gründen, die Hunderte von Malen bedeuten) genannt wird eine Sekunde):
Delay(0)
anders umzugehen?return Task.Run(() => { });
anders?Gibt es einen besseren Weg?
using System.Threading.Tasks;
namespace MyAsyncTest
{
internal interface IFooFace
{
Task WillBeLongRunningAsyncInTheMajorityOfImplementations();
}
/// <summary>
/// An implementation, that unlike most cases, will not have a long-running
/// operation in 'WillBeLongRunningAsyncInTheMajorityOfImplementations'
/// </summary>
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<int>(12345);
}
#endregion
}
internal class Program
{
private static void Main(string[] args)
{
Test();
}
private static async void Test()
{
IFooFace foo = FactoryCreate();
await foo.WillBeLongRunningAsyncInTheMajorityOfImplementations();
return;
}
private static IFooFace FactoryCreate()
{
return new LazyBar();
}
}
}
Die Verwendung von Task.FromResult(0)
oder Task.FromResult<object>(null)
verursacht weniger Aufwand als das Erstellen eines Task
mit einem No-Op-Ausdruck. Beim Erstellen eines Task
mit einem zuvor festgelegten Ergebnis ist kein Planungsaufwand erforderlich.
Heute würde ich empfehlen, Task.CompletedTask zu verwenden, um dies zu erreichen.
Hinzufügen zu Reed Copseys Antwort über die Verwendung von Task.FromResult
, Sie können die Leistung noch weiter verbessern, wenn Sie die bereits abgeschlossene Aufgabe zwischenspeichern, da alle Instanzen abgeschlossener Aufgaben gleich sind:
public static class TaskExtensions
{
public static readonly Task CompletedTask = Task.FromResult(false);
}
Mit TaskExtensions.CompletedTask
Sie können dieselbe Instanz in der gesamten App-Domäne verwenden.
Die neueste Version von .Net Framework (v4.6) fügt genau das mit Task.CompletedTask
statische Eigenschaft
Task completedTask = Task.CompletedTask;
Task.Delay(0)
wie in der akzeptierten Antwort war ein guter Ansatz, da es sich um eine zwischengespeicherte Kopie eines vollständigen Task
handelt.
Ab 4.6 gibt es nun Task.CompletedTask
, Was in seinem Zweck genauer ist, aber nicht nur, dass Task.Delay(0)
immer noch eine einzelne zwischengespeicherte Instanz zurückgibt, sondern auch die selbe einzelne zwischengespeicherte Instanz Instanz wie Task.CompletedTask
.
Die zwischengespeicherte Natur von keinem bleibt garantiert konstant, aber als implementierungsabhängige Optimierungen, die nur als Optimierungen implementierungsabhängig sind (das heißt, sie würden immer noch korrekt funktionieren, wenn die Implementierung auf etwas geändert würde, das noch gültig ist), die Verwendung von Task.Delay(0)
war besser als die akzeptierte Antwort.
Dies ist kürzlich aufgetreten und es werden immer wieder Warnungen/Fehler angezeigt, dass die Methode ungültig ist.
Wir sind im Geschäft, den Compiler zu beschwichtigen, und das klärt es auf:
public async Task MyVoidAsyncMethod()
{
await Task.CompletedTask;
}
Dies bringt das Beste aller Ratschläge zusammen, die bisher hier gegeben wurden. Eine return-Anweisung ist nur erforderlich, wenn Sie tatsächlich etwas in der Methode tun.
Wenn Sie den angegebenen Typ zurückgeben müssen:
Task.FromResult<MyClass>(null);
Ich bevorzuge die Task completedTask = Task.CompletedTask;
Lösung von .Net 4.6, aber ein anderer Ansatz besteht darin, die Methode als asynchron zu markieren und void zurückzugeben:
public async Task WillBeLongRunningAsyncInTheMajorityOfImplementations()
{
}
Sie erhalten eine Warnung (CS1998 - Async-Funktion ohne Wartezeitausdruck), die Sie in diesem Kontext jedoch ignorieren können.
return Task.CompletedTask; // this will make the compiler happy