Es funktioniert ähnlich wie das Schlüsselwort yield return
in C# 2.0.
Eine asynchrone Methode ist keine gewöhnliche sequentielle Methode. Es wird in eine Zustandsmaschine (ein Objekt) mit einem bestimmten Zustand kompiliert (lokale Variablen werden in Felder des Objekts umgewandelt). Jeder Codeblock zwischen zwei Verwendungen von await
ist ein "Schritt" der Zustandsmaschine.
Dies bedeutet, dass beim Starten der Methode nur der erste Schritt ausgeführt wird und dann die Zustandsmaschine zurückkehrt und einige zu erledigende Aufgaben einplant - wenn die Arbeit erledigt ist, wird der nächste Schritt der Zustandsmaschine ausgeführt. Zum Beispiel dieser Code:
async Task Demo() {
var v1 = foo();
var v2 = await bar();
more(v1, v2);
}
möchte etwas übersetzt werden:
class _Demo {
int _v1, _v2;
int _state = 0;
Task<int> _await1;
public void Step() {
switch(this._state) {
case 0:
this._v1 = foo();
this._await1 = bar();
// When the async operation completes, it will call this method
this._state = 1;
op.SetContinuation(Step);
case 1:
this._v2 = this._await1.Result; // Get the result of the operation
more(this._v1, this._v2);
}
}
Der wichtigste Teil ist, dass es nur die SetContinuation
Methode verwendet, um anzugeben, dass, wenn der Vorgang abgeschlossen ist, sollte es die Step
nennen Methode (und die Methode weiß, dass das zweite Bit des ursprünglichen Codes mit dem Feld _state
ausgeführt werden soll). Sie können sich leicht vorstellen, dass die SetContinuation
so etwas wie btn.Click += Step
wäre, die komplett auf einem einzigen Thread laufen würde. Das asynchrone Programmiermodell in C# ähnelt sehr den asynchronen F # -Arbeitsabläufen (abgesehen von einigen technischen Details ist es im Wesentlichen dasselbe) und das Schreiben reaktiver single-threaded-GUI-Anwendungen unter Verwendung von async
ist ein ziemlich interessanter Bereich - zumindest denke ich - siehe zum Beispiel this article (vielleicht sollte ich jetzt eine C# Version schreiben :-)).
Die Übersetzung ähnelt Iteratoren (und yield return
) und tatsächlich war es möglich, Iteratoren zu verwenden, um die asynchrone Programmierung in C# früher zu implementieren. Ich schrieb vor einer Weile an article about that - und ich denke, dass es Ihnen noch einige Einblicke geben kann, wie die Übersetzung funktioniert.
Wie ist es ohne einen separaten Thread geplant? Ist eine Fortsetzung ein spezifisches Konzept in der CLR, das eine leichte Planung erlaubt? –
@ 0xA3: Ich glaube, das Papier sagt, dass die Async-Methode nicht auf einem eigenen Thread läuft. I.e. genau wie TPL wird es eine Mischung aus den aktuellen Thread- und Thread-Pool-Threads sein, abhängig von der Situation. –