Frage

Ich sehe nicht den Unterschied zwischen C # 's (und VB) neuen Asynchron-Features und .NET 4.0 ist Task-Bibliothek Parallel. Nehmen wir zum Beispiel, Eric Lippert Code von hier :

async void ArchiveDocuments(List<Url> urls) {
    Task archive = null;
    for(int i = 0; i < urls.Count; ++i) {
        var document = await FetchAsync(urls[i]);
        if (archive != null)
            await archive;
        archive = ArchiveAsync(document);
    }
}

Es scheint, dass die await Schlüsselwort zwei verschiedenen Zwecken dient. Das erste Auftreten (FetchAsync) scheint zu bedeuten, „Wenn dieser Wert verwendet wird später in dem Verfahren und seine Aufgabe nicht fertig ist, warten, bis es abgeschlossen ist, bevor Sie fortfahren.“ die zweite Instanz (archive) zu bedeuten scheint, „Wenn diese Aufgabe ist noch nicht fertig, wartet jetzt , bis er abgeschlossen ist.“ Wenn ich falsch bin, bitte korrigieren sie mich, .

Könnte es nicht genauso einfach wie folgt geschrieben werden?

void ArchiveDocuments(List<Url> urls) {
    for(int i = 0; i < urls.Count; ++i) {
        var document = FetchAsync(urls[i]);       // removed await
        if (archive != null)
            archive.Wait();                       // changed to .Wait()
        archive = ArchiveAsync(document.Result);  // added .Result
    }
}

habe ich das erste await mit einem Task.Result ersetzt, wenn der Wert tatsächlich benötigt wird, und den zweiten await mit Task.Wait(), wo das Warten tatsächlich auftritt. Die Funktionalität ist (1) bereits umgesetzt, und (2) viel näher semantisch zu dem, was geschieht eigentlich im Code.

ich erkennen, dass ein async Methode als eine Zustandsmaschine neu geschrieben wird, ähnlich wie Iteratoren, aber ich sehe auch nicht, was Vorteile, die sich bringt. Jeder Code, der einen anderen Thread erfordert (wie das Herunterladen) betreiben noch einen weiteren Thread benötigt, und jeder Code, der nicht (wie aus einer Datei liest) konnte immer noch den TPL zur Arbeit mit nur einem einzigen Thread nutzen.

Ich bin fehlt offensichtlich etwas Großes hier; Kann jemand mir helfen zu verstehen dies ein wenig besser?

War es hilfreich?

Lösung

Ich denke, das Mißverständnis entsteht hier:

  

Es scheint, dass das await Schlüsselwort zwei verschiedenen Zwecken dient. Das erste Auftreten (FetchAsync) scheint zu bedeuten: „Wenn dieser Wert später in dem Verfahren verwendet wird, und seine Aufgabe ist noch nicht fertig, warten, bis sie vor dem Fortfahren abgeschlossen ist.“ Die zweite Instanz (Archiv) scheint zu bedeuten: „Wenn diese Aufgabe noch nicht abgeschlossen ist, wartet jetzt, bis es abgeschlossen ist.“ Wenn ich falsch bin, kann man mich korrigieren.

Dies ist eigentlich völlig falsch. Beide haben die gleiche Bedeutung.

Im ersten Fall:

var document = await FetchAsync(urls[i]);

Was hier passiert, ist, dass die Laufzeit sagt „Start FetchAsync Aufruf, dann wieder den aktuellen Ausführungspunkt an dem Thread diese Methode aufrufen.“ Es gibt keine „warten“ hier - stattdessen kehrt die Ausführung zu dem anrufenden Synchronisationskontext, und die Dinge am laufenden Band. An einem gewissen Punkt in der Zukunft wird FetchAsync die Aufgabe abzuschließen, und an diesem Punkt wird dieser Code wieder auf den Synchronisationskontext des rufenden Thread, und die nächste Anweisung (Zuweisung die Dokumentvariable) auftreten wird.

Die Ausführung wird dann bis zum zweiten await Gespräch weiterführen - und zu diesem Zeitpunkt wird das Gleiche passieren - wenn der Task<T> (Archiv) nicht abgeschlossen ist, wird die Ausführung an dem anrufenden Kontext freigegeben werden - andernfalls wird die Archiv-Set sein .

Im zweiten Fall sind die Dinge ganz anders - hier sind Sie ausdrücklich zu blockieren, was bedeutet, dass der anrufende Synchronisationskontext wird nie eine Chance bekommen einen Code, bis das gesamte Verfahren abgeschlossen ist auszuführen. Zugegeben, das ist immer noch da Asynchronität, aber die Asynchronität vollständig innerhalb dieses Blocks von Code enthalten -. Ohne Code außerhalb dieses eingefügten Code auf diesen Thread, bis alle Codes abgeschlossen ist geschehen

Andere Tipps

Es gibt einen großen Unterschied:

Wait() Blöcke, await nicht blockiert. Wenn Sie die asynchrone Version von ArchiveDocuments() auf Ihrem GUI-Thread ausgeführt wird, wird die GUI bleiben anspricht, während die das Abrufen und die Archivierung von Operationen ausgeführt werden. Wenn Sie die TPL-Version mit Wait() verwenden, wird Ihre GUI blockiert werden.

Beachten Sie, dass async dies zu tun verwaltet, ohne Gewinde Einführung - an der Stelle des await, wird die Steuerung einfach an die Nachrichtenschleife zurück. Sobald die Aufgabe abgeschlossen gewartet wird, wird der Rest des Verfahrens (Fortsetzung) auf der Nachrichtenschleife eine Warteschlange eingereiht und die GUI-Thread weiterhin ArchiveDocuments läuft, wo er unterbrochen wurde.

Anders kochte es auf eine sehr prägnante Antwort im Channel 9 Live Interview, das er getan hat. Ich kann es sehr empfehlen

Die neue Async und await Schlüsselwörter können Sie auf orchestrate Gleichzeitigkeit in Ihren Anwendungen. Sie haben nicht wirklich vorstellen jede Parallelität in Ihrer Anwendung.

TPL und insbesondere Aufgabe ist eine Art und Weise Sie tatsächlich nutzen können Operationen gleichzeitig ausführen. Die neue async und await Schlüsselwort können Sie auf compose diese gleichzeitigen Vorgänge in einem „synchronen“ oder „linear“ Art und Weise.

So können Sie immer noch einen linearen Ablauf der Steuerung in Ihren Programmen schreiben, während die eigentlichen Rechen können oder nicht gleichzeitig passieren können. Wenn die Berechnung gleichzeitig geschieht, await und async können Sie auf compose diese Operationen.

Die Möglichkeit, den Programmablauf der Steuerung in einer Zustandsmaschine zu drehen ist, was diese neuen Keywords macht intresting. Betrachten Sie es als Nachgeben Kontrolle , anstatt Werte.

Sehen Sie sich diesen Channel 9 Video von Anders reden die neue Funktion.

Das Problem hierbei ist, dass die Unterschrift von ArchiveDocuments ist irreführend. Es hat eine explizite Rückkehr von void aber wirklich die Rückkehr ist Task. Für mich Leere bedeutet synchron, da es keine Möglichkeit, „Wartezeit“ ist für sie zu beenden. Betrachten Sie die alternative Signatur der Funktion.

async Task ArchiveDocuments(List<Url> urls) { 
  ...
}

Für mich, wenn es auf diese Weise geschrieben ist der Unterschied viel offensichtlicher ist. Die ArchiveDocuments Funktion ist nicht eine, die synchron vervollständigt aber später fertig wird.

Der Aufruf von FetchAsync() noch blockiert, bis sie abgeschlossen ist (es sei denn, eine Anweisung innerhalb Anrufe await?) Der Schlüssel ist, dass die Steuerung an den Aufrufer zurückgegeben (da die ArchiveDocuments Methode selbst als async erklärt wird). So ist der Anrufer glücklich kann weiterhin UI-Logik der Verarbeitung reagieren auf Ereignisse, usw.

Wenn FetchAsync() abgeschlossen ist, ist es den Anrufer unterbricht die Schleife zu beenden. Es trifft ArchiveAsync() und blockiert, aber ArchiveAsync() wahrscheinlich erzeugt nur eine neue Aufgabe, beginnt sie, und gibt die Aufgabe. Dies ermöglicht die zweite Schleife zu beginnen, während die Aufgabe bearbeitet.

Die zweite Schleife trifft FetchAsync() und Blöcke, die Kontrolle an den Aufrufer zurück. Wenn FetchAsync() abgeschlossen ist, ist es wieder den Anrufer unterbricht die Verarbeitung fortzusetzen. Es trifft dann await archive, die zurückkehrt, bis die Task in Schleife 1 abgeschlossen ist geschaffen, um den Anrufer zu steuern. Sobald dieser Vorgang abgeschlossen ist, wird der Anrufer wieder unterbrochen, und die zweite Schleife ruft ArchiveAsync(), die eine gestartete Task bekommt und beginnt Schleife 3, wiederholen Sie bis zum Überdruss .

Der Schlüssel wird die Steuerung an den Aufrufer zurückkehrt, während die schweren Heber ausgeführt werden.

Das await Schlüsselwort führt keine Gleichzeitigkeit. Es ist wie die Ausbeute Schlüsselwort, es weist den Compiler zur Umstrukturierung des Code in Lambda durch eine Zustandsmaschine gesteuert.

Um zu sehen, was await Code aussehen würde ohne 'await' sieht diesen hervorragenden Link: http://blogs.msdn.com/b/windowsappdev/archive/2012/04/24/diving-deep-with-winrt-and-await aspx

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top