Was ist die Verwendung für Task.FromResult <TResult> in C #

189

In C # und TPL ( Task Parallel Library ) stellt die TaskKlasse eine laufende Arbeit dar, die einen Wert vom Typ T erzeugt.

Ich möchte wissen, was für die Task.FromResult- Methode erforderlich ist.

Das heißt: In einem Szenario, in dem Sie den produzierten Wert bereits zur Hand haben, was ist die Notwendigkeit, ihn wieder in eine Aufgabe zu packen?

Das einzige, was mir in den Sinn kommt, ist, dass es als Adapter für andere Methoden verwendet wird, die eine Task-Instanz akzeptieren.

Lysergsäure
quelle
30
Bis zu einem gewissen Grad stimme ich dem zu, aber die Erstellung dichter, nützlicher, konsolidierter, diskussionsorientierter Seiten wie dieser ist ein großer Vorteil. Ich lerne fast immer mehr von einer guten, dichten Stackoverflow-Seite als von googeln und recherchieren an mehreren Stellen. In diesem Fall bin ich wirklich froh, dass er dies gepostet hat.
Alex Edelstein
41
Ich denke, Google bringt mich zu SO und SO bittet mich, zu Google zu gehen. Es ist ein
Zirkelverweis

Antworten:

257

Ich habe zwei häufige Anwendungsfälle gefunden:

  1. Wenn Sie eine Schnittstelle implementieren, die asynchrone Anrufer zulässt, Ihre Implementierung jedoch synchron ist.
  2. Wenn Sie asynchronen Code zum Testen stubben / verspotten.
Stephen Cleary
quelle
6
Ein guter Fall für # 1 ist ein Webdienst. Sie könnten eine synchrone Dienstmethode haben, die zurückgibt, Task.FromResultund einen Client, der asynchron auf die Netzwerk-E / A wartet. Auf diese Weise können Sie dieselbe Schnittstelle zwischen Client / Server verwenden ChannelFactory.
Nelson Rothermel
2
Zum Beispiel die ChallengeAsync-Methode. WTF dachten die Designer bei MS? Es gibt absolut keinen Grund für diese Methode, eine Aufgabe zurückzugeben. Und der gesamte Beispielcode von MS hat einfach FromResult (0). Hoffentlich ist der Compiler klug genug, um dies zu optimieren, und erzeugt keinen neuen Thread und beendet ihn dann sofort!
John Henckel
14
@ JohnHenckel: OWIN wurde von Grund auf asynchronisiert. Schnittstellen und Basisklassen oft async Signaturen verwenden , da es nur erlaubt (nicht Kräfte ) die Umsetzung sein async. So ist es zu ähnlich ist IEnumerable<T>aus abzuleiten IDisposable- es ermöglicht die zählbare Einweg Ressourcen zu haben, nicht Kräfte es. Weder FromResult, asyncnoch awaitwerden Threads erzeugen.
Stephen Cleary
4
@ StephenCleary hmhm, danke für die Erklärung. Ich hatte angenommen, dass das Warten auftauchen würde, aber ich habe es versucht und ich sehe, dass es nicht so ist. Nur Task.Run funktioniert. Daher ist x = warte auf Task.FromResult (0); ist gleichbedeutend mit x = 0; das ist verwirrend, aber gut zu wissen!
John Henckel
4
@OlegI: Für E / A-Vorgänge besteht die beste Lösung darin, sie asynchron zu implementieren, aber manchmal haben Sie diese Wahl nicht. Auch, manchmal Sie können es synchron implementieren (zB ein im Cache gespeicherte Ergebnis auf eine asynchrone Implementierung zurückzufallen , wenn der Wert nicht zwischengespeichert wird). Allgemeiner Taskbedeutet ein Rückgabemethode " kann asynchron sein". Daher erhalten Methoden manchmal eine asynchrone Signatur, wobei sie genau wissen, dass einige Implementierungen synchron sind (z. B. NetworkStreamsollten asynchron sein, aber MemoryStreamsynchron sein).
Stephen Cleary
50

Ein Beispiel wäre eine Methode, die einen Cache verwendet. Wenn das Ergebnis bereits berechnet wurde, können Sie eine abgeschlossene Aufgabe mit dem Wert (using Task.FromResult) zurückgeben. Wenn dies nicht der Fall ist, geben Sie eine Aufgabe zurück, die die laufende Arbeit darstellt.

Cache-Beispiel: Cache-Beispiel mit Task.FromResult für vorberechnete Werte

Matt Smith
quelle
Abgeschlossene Aufgaben, z. B. die zurückgegebenen Task.FromResult, können zwischengespeichert werden.
Paulo Morgado
1
@Paulo: Das Speichern des gesamten Task-Objekts scheint weitaus verschwenderischer zu sein, als nur das Ergebnis zwischenzuspeichern.
Ben Voigt
2
Erwarten Sie, dass "Wertaufgaben" bereits zwischengespeichert sind. Ich erinnere mich nicht genau , welche diejenigen, aber ich denke Task.FromResult(0), Task.FromResult(1), Task.FromResult(false)und Task.FromResult(true)zwischengespeichert werden. Sie sollten keine Aufgabe für einen Netzwerkzugriff zwischenspeichern, aber eine aus dem Ergebnis ist vollkommen in Ordnung. Möchten Sie es vorziehen, jedes Mal eine zu erstellen, wenn Sie den Wert zurückgeben müssen?
Paulo Morgado
4
... und um meine eigene Frage zu beantworten, der Vorteil eines Caches mit Aufgaben besteht darin, dass einige von ihnen erledigte Aufgaben sein können und andere noch nicht erledigte. Anrufer müssen sich nicht darum kümmern: Sie führen einen asynchronen Anruf durch. Wenn dieser bereits abgeschlossen ist, erhalten sie sofort eine Antwort, wenn sie warten. Wenn nicht, erhalten sie ihn später. Ohne diese zwischengespeicherten Aufgaben wären entweder (a) zwei verschiedene Mechanismen erforderlich, eine Synchronisierung und eine asynchrone - umständlich für den Anrufer, oder (b) müssten jedes Mal, wenn ein Anrufer nach einer Antwort fragt, die bereits verfügbar ist, dynamisch eine Aufgabe erstellen (wenn wir hatten nur ein TResult zwischengespeichert).
ToolmakerSteve
1
Ich verstehe es jetzt. Der Wortlaut der Antwort war etwas verwirrend. Die Aufgabe selbst verfügt nicht über einen integrierten "Caching" -Mechanismus. Wenn Sie jedoch einen Caching-Mechanismus zum Herunterladen von Dateien geschrieben haben, z. B. Task <Datei> GetFileAync (), können Sie mithilfe von Task.FromResult (cachedFile) und dem Warten sofort eine Datei zurückgeben, die sich bereits im Cache befindet würde synchron laufen und Zeit sparen, wenn der Thread-Schalter nicht vorhanden wäre.
Brain2000
31

Verwenden Sie diese Option, wenn Sie eine erwartete Methode erstellen möchten, ohne das Schlüsselwort async zu verwenden. Ich habe dieses Beispiel gefunden:

public class TextResult : IHttpActionResult
{
    string _value;
    HttpRequestMessage _request;

    public TextResult(string value, HttpRequestMessage request)
    {
        _value = value;
        _request = request;
    }
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage()
        {
            Content = new StringContent(_value),
            RequestMessage = _request
        };
        return Task.FromResult(response);
    }
}

Hier erstellen Sie Ihre eigene Implementierung der IHttpActionResult-Schnittstelle, die in einer Web-API-Aktion verwendet werden soll. Es wird erwartet, dass die ExecuteAsync-Methode asynchron ist, aber Sie müssen das Schlüsselwort async nicht verwenden, um sie asynchron und wartbar zu machen. Da Sie bereits das Ergebnis haben und nichts abwarten müssen, ist es besser, Task.FromResult zu verwenden.

Edminsson
quelle
20

Von MSDN:

Diese Methode ist nützlich, wenn Sie eine asynchrone Operation ausführen, die ein Task-Objekt zurückgibt, und das Ergebnis dieses Task-Objekts bereits berechnet wurde.

http://msdn.microsoft.com/en-us/library/hh228607.aspx

goughy000
quelle
4

Verwenden Sie Task.FromResult, wenn Sie eine asynchrone Operation ausführen möchten, das Ergebnis jedoch manchmal synchron vorliegt. Ein gutes Beispiel finden Sie hier http://msdn.microsoft.com/en-us/library/hh228607.aspx .

Alborz
quelle
In Ihrem guten Beispiel ist das Ergebnis nicht synchron in der Hand, die Operation ist vollständig asynchron und Task.FromResultwird verwendet, um ein zuvor zwischengespeichertes asynchrones Ergebnis zu erhalten.
Rodrigo Reis
1

Ich würde argumentieren, dass Sie Task.FromResult für synchrone Methoden verwenden könnten, deren Fertigstellung lange dauert, während Sie andere unabhängige Arbeiten in Ihrem Code ausführen können. Ich würde diese Methoden lieber dazu bringen, asynchron aufzurufen. Stellen Sie sich jedoch die Situation vor, in der Sie keine Kontrolle über den aufgerufenen Code haben und diese implizite Parallelverarbeitung wünschen.

Wikinger
quelle