it-swarm.com.de

Was ist der Unterschied zwischen der Rückgabe von ungültigen und einer Aufgabe?

Wenn ich mir verschiedene C # Async-CTP-Beispiele ansehe, sehe ich einige asynchrone Funktionen, die void zurückgeben, und andere, die das nicht generische Task zurückgeben. Ich kann sehen, warum ein Task<MyType> ist nützlich, um Daten an den Aufrufer zurückzugeben, wenn der asynchrone Vorgang abgeschlossen ist, aber die Funktionen, die ich gesehen habe und die den Rückgabetyp Task haben, geben niemals Daten zurück. Warum nicht void zurückgeben?

120
James Cadd

SLaks und Killercams Antworten sind gut; Ich dachte, ich würde nur etwas mehr Kontext hinzufügen.

Bei Ihrer ersten Frage geht es im Wesentlichen darum, welche Methoden als async gekennzeichnet werden können.

Eine als async markierte Methode kann void, Task oder Task<T> Zurückgeben. Was sind die Unterschiede zwischen ihnen?

Eine Task<T> Zurückgegebene asynchrone Methode kann abgewartet werden, und wenn die Aufgabe abgeschlossen ist, wird ein T angeboten.

Eine asynchrone Methode, die Task zurückgibt, kann abgewartet werden, und wenn die Aufgabe abgeschlossen ist, ist die Ausführung der Fortsetzung der Aufgabe geplant.

Eine void zurückgebende asynchrone Methode kann nicht erwartet werden; Es ist eine "Feuer und Vergessen" -Methode. Es funktioniert asynchron und Sie können nicht sagen, wann es fertig ist. Das ist mehr als ein bisschen komisch; Wie SLaks sagt, würden Sie dies normalerweise nur tun, wenn Sie einen asynchronen Ereignishandler erstellen. Das Ereignis wird ausgelöst, der Handler wird ausgeführt. niemand wird die vom Ereignishandler zurückgegebene Aufgabe "abwarten", da Ereignishandler keine Aufgaben zurückgeben, und selbst wenn dies der Fall wäre, welcher Code würde die Aufgabe für etwas verwenden? Normalerweise überträgt kein Benutzercode die Kontrolle an den Handler.

Bei Ihrer zweiten Frage in einem Kommentar geht es im Wesentlichen darum, was awaited sein kann:

Welche Arten von Methoden können awaited sein? Kann eine Methode zur Rückgabe von Leerräumen awaited sein?

Nein, es kann nicht auf eine Methode zur Stornierung gewartet werden. Der Compiler übersetzt await M() in einen Aufruf von M().GetAwaiter(), wobei GetAwaiter eine Instanzmethode oder eine Erweiterungsmethode sein kann. Der erwartete Wert muss einer sein, für den Sie einen Kellner bekommen können; Offensichtlich liefert eine Methode zur Rückgabe von Leerräumen keinen Wert, von dem Sie einen Kellner erhalten können.

Task- Rückgabemethoden können erwartete Werte erzeugen. Wir gehen davon aus, dass Dritte ihre eigenen Implementierungen von Task -ähnlichen Objekten erstellen möchten, auf die gewartet werden kann, und Sie können sie erwarten. Sie dürfen jedoch keine async Methoden deklarieren, die etwas anderes als void, Task oder Task<T> Zurückgeben.

(UPDATE: Mein letzter Satz wird möglicherweise von einer zukünftigen Version von C # verfälscht. Es gibt einen Vorschlag, andere Rückgabetypen als Aufgabentypen für asynchrone Methoden zuzulassen.)

(UPDATE: Die oben erwähnte Funktion hat es in C # 7 geschafft.)

201
Eric Lippert

Falls der Anrufer auf die Aufgabe warten oder eine Fortsetzung hinzufügen möchte.

Tatsächlich ist der einzige Grund, void zurückzugeben, wenn Sie kann nichtTask zurückgeben, weil Sie einen Ereignishandler schreiben.

22
SLaks

Methoden, die Task und Task<T> Zurückgeben, können zusammengesetzt werden. Das bedeutet, dass Sie await innerhalb einer async -Methode angeben können.

async Methoden, die void zurückgeben, können nicht zusammengesetzt werden, haben jedoch zwei weitere wichtige Eigenschaften:

  1. Sie können als Ereignishandler verwendet werden.
  2. Sie stellen eine asynchrone Operation auf "oberster Ebene" dar.

Der zweite Punkt ist wichtig, wenn Sie mit einem Kontext arbeiten, der eine Anzahl der ausstehenden asynchronen Operationen verwaltet.

Der ASP.NET-Kontext ist ein solcher Kontext. Wenn Sie asynchrone Task Methoden verwenden, ohne sie von einer asynchronen void Methode abzuwarten, wird die ASP.NET-Anforderung zu früh ausgeführt.

Ein weiterer Kontext ist das AsyncContext, das ich für Unit-Tests geschrieben habe (verfügbar hier ) - Die Methode AsyncContext.Run Verfolgt die Anzahl der ausstehenden Operationen und gibt sie zurück, wenn sie Null ist.

18
Stephen Cleary

Typ Task<T> Ist der Arbeitspferdetyp der Task Parallel Library (TPL). Er repräsentiert das Konzept "einer Arbeit/eines Jobs, die/der in Zukunft ein Ergebnis vom Typ T erzeugen wird". Das Konzept "Arbeit, die in Zukunft abgeschlossen sein wird, aber kein Ergebnis zurückgibt" wird durch den nicht generischen Aufgabentyp dargestellt.

Wie genau das Ergebnis vom Typ T erzeugt werden soll, ist ein Implementierungsdetail einer bestimmten Aufgabe. Die Arbeit wird möglicherweise auf einen anderen Prozess auf dem lokalen Computer, auf einen anderen Thread usw. übertragen. TPL-Tasks werden normalerweise auf Arbeitsthreads aus einem Threadpool im aktuellen Prozess übertragen, aber diese Implementierungsdetails sind für Task<T> Type; Vielmehr kann ein Task<T> jede Operation mit hoher Latenz darstellen, die ein T erzeugt.

Basierend auf Ihrem obigen Kommentar:

Der Ausdruck await bedeutet "diesen Ausdruck auswerten, um ein Objekt zu erhalten, das eine Arbeit darstellt, die in Zukunft ein Ergebnis hervorbringt. Den Rest der aktuellen Methode als Rückruf für die Fortsetzung dieser Aufgabe eintragen. Nach dieser Aufgabe wird erzeugt und der Rückruf wird angemeldet, sofort Kontrolle an meinen Anrufer zurückgeben ". Dies steht im Gegensatz zu einem regulären Methodenaufruf, der bedeutet: "Merke dir, was du tust, führe diese Methode aus, bis sie vollständig abgeschlossen ist, und greife dann dort auf, wo du aufgehört hast, und kenne jetzt das Ergebnis der Methode.".


Edit: Ich sollte Eric Lipperts Artikel im MSDN Magazine vom Oktober 2011 zitieren, da dies eine große Hilfe für mich war, um dieses Zeug überhaupt zu verstehen.

Weitere Informationen und Whitepages finden Sie unter hier .

Ich hoffe, das ist hilfreich.

12
MoonKnight