async + wait == sync?

24

Stolperte über diesen Beitrag , in dem es darum geht, asynchrone Webanfragen zu stellen.

Abgesehen von der Einfachheit, wenn Sie in der realen Welt nur eine asynchrone Anfrage stellen und in der nächsten Zeile darauf warten, ist das nicht gleichbedeutend mit einem Synchronisierungsanruf?

Mrchief
quelle
5
Nicht genau. Ihr Code ist in einem Sinne synchron, dass nichts passiert, bis Sie ein Ergebnis erhalten. Darunter haben Sie wahrscheinlich den Thread, auf dem Sie ausgeführt haben, aufgegeben, bis die asynchrone Methode zurückgegeben wurde, und dann einen anderen Thread zugewiesen bekommen, um mit der Ausführung fortzufahren.
R0MANARMY
2
es ist aber mit async kannst du gleichzeitig eine weitere async machen und dann die 2 abwarten, mit sync ist das nicht möglich
ratschenfreak
Hier ist ein Artikel ( tomasp.net/blog/async-compilation-internals.aspx ), in dem einige Aspekte der asynchronen Programmierung in C # und F # behandelt werden.
Paul
@ratchetfreak: Ja, das versteht sich von selbst, wenn Sie mehrere Anrufe tätigen.
Mrchief
@ R0MANARMY: Wenn Ihre App andere Aufgaben ausführt, wird dies durch yes und async + await aktiviert . Akim sagt es am besten! Stellen Sie sich jedoch vor, der Code befindet sich nicht im button_click-Handler oder in einem solchen Event-Handler. Wenn jemand den Code blind kopiert (asynchron + Wartezeilen), kann dies zu dem falschen Eindruck führen, dass Ihr Code asynchron ist, dies jedoch möglicherweise nicht der Fall ist.
Mrchief

Antworten:

32

Nein async + await != sync, wegen der Fortsetzung

Aus MSDN "Asynchrone Programmierung mit Async und Await (C # und Visual Basic)"

Asynchrone Methoden sollen nicht blockierende Operationen sein. Ein wait-Ausdruck in einer asynchronen Methode blockiert den aktuellen Thread nicht, während die erwartete Task ausgeführt wird. Stattdessen meldet der Ausdruck den Rest der Methode als Fortsetzung an und gibt die Steuerung an den Aufrufer der asynchronen Methode zurück .

Beispielsweise blockiert die asynchrone Ausführung den UI-Thread nicht und Some TextBox.Textwird nach Abschluss des Downloads aktualisiert

private async void OnButtonClick()
{
   SomeTextBox.Text = await new WebClient().DownloadStringTaskAsync("http://stackoverflow.com/");
}
Akim
quelle
Sehr schön gesagt!
Mrchief
Könnten Sie das näher erläutern? Wollen Sie damit sagen, dass Sie ohne dies nicht in der Lage wären, mit der Benutzeroberfläche zu interagieren, da dies im Haupt-Thread wäre? Dies bedeutet also, dass dies nur in einem Programm vom Typ "Anwendung" für das Web anwendbar ist, bei dem die Interaktion vom Webserver-Thread getrennt ist. In einer Nussschale wird dies nur dann wichtig, wenn Ihr Hauptthread der laufende Thread ist. Würde dies nicht zu unerwartetem Verhalten führen, dh in einer App (1 Haupt-Thread) wurden zwei Schaltflächen angeklickt. Sie sollten jedoch in der Lage sein, auf die 1 zu klicken, ohne dass die erste abgeschlossen wird?
Seabizkit
Was ist Console.WriteLine(await GetStringOverNetwork());? Was ist, wenn Sie die Ausgabe des asynchronen Aufrufs benötigen? Würde das Programm beim ersten Zugriff blockieren, selbst wenn der Thread möglicherweise die Ausführung fortsetzen könnte?
Andrew
6

Nein, es ist nicht dasselbe.

Ihr asyncCodeblock wartet auf die awaitRückkehr des Aufrufs, um fortzufahren. Der Rest Ihrer Anwendung wartet jedoch nicht und kann wie gewohnt fortgesetzt werden.

Im Gegensatz dazu würde ein synchroner Aufruf Ihre gesamte Anwendung oder Ihren gesamten Thread warten lassen, bis die Ausführung des Codes abgeschlossen ist, um mit etwas anderem fortzufahren.

Rachel
quelle
Konnte der Sync-Aufruf nicht als async + await implementiert werden?
Ratschenfreak
@ratchetfreak Ich glaube, das Einrichten von wait / async ist mit einem gewissen Aufwand verbunden, sodass ich nicht glaube, dass Sie Ihre gesamte Anwendung damit codieren möchten. Ich verwende es nur zum Ausführen von möglicherweise lang laufenden Codeblöcken, damit meine Anwendungen nicht blockiert werden. :)
Rachel
5

Bitte erlauben Sie mir, die Dinge in Bezug auf async / await zu klären.

Wenn Warten auftritt, ermöglicht die zugrunde liegende Zustandsmaschine die sofortige Rückgabe der Steuerung. Wenn der erwartete Aufruf abgeschlossen ist, ermöglicht die zugrunde liegende Zustandsmaschine, dass die Ausführung an der Leitung nach dem erwarteten Aufruf fortgesetzt wird.

Daher wird der asynchrone Block nicht blockiert und wartet nicht auf den Abschluss des erwarteten Aufrufs. Die Steuerung wird sofort zurückgegeben, wenn der Befehl await auftritt.

Die zugrunde liegende Zustandsmaschine ist Teil der "Magie" hinter der Verwendung von async / await, die nicht ungenutzt bleibt und übersehen wird.

Cedric Harris
quelle
2

Ich bin mit der gleichen Frage darüber gestolpert, doch nach dem Lesen der Antworten scheint die Frage zu verweilen, verwirrt durch Verweise auf "Magie unter der Haube".

Aus der oben erwähnten asynchronen Programmierung :

  • Das asyncSchlüsselwort verwandelt eine Methode in eine asynchrone Methode, mit der Sie das awaitSchlüsselwort in seinem Hauptteil verwenden können.
  • Wenn das awaitSchlüsselwort angewendet wird, setzt es die aufrufende Methode aus und gibt die Kontrolle an seinen Aufrufer zurück, bis die erwartete Aufgabe abgeschlossen ist.
  • awaitkann nur innerhalb einer asyncMethode verwendet werden.

Wird der Kontext, in dem Begegnungen stattfinden await, blockiert?

  • Ja . Dies ist im Wesentlichen eine lokale Synchronisationssperre, um einen bekannten Zustand im Kontext der Ausführung beizubehalten. mit der Ausnahme, dass andere Kontexte, falls vorhanden, nicht verbunden werden.

Blockiert der Rest der Anwendung das await?

  • Es hängt davon ab, wie Ihre Bewerbung geschrieben ist. Wenn es sich um eine Reihe von abhängigen awaitAufgaben handelt, die nacheinander im selben Kontext gestartet werden (siehe: Versuchen, ein gewisses Async / Wartet-Verhalten zu verstehen )

    await asyncCall1();
    await asyncCall2();  // waits for asyncCall1() to complete

    Auf diese Weise awaitwürde jeder das Laichen des nächsten blockieren.

    Andererseits würden die gleichen abhängigen Aufgaben, die parallel gestartet werden, parallel ausgeführt und der Kontext würde nur an der entsprechenden Stelle blockiert. await:

    Task<int> t1 = asyncCall1();
    Task<string> t2 = asyncCall2();  // runs in parallel with asyncCall1()
    int val = await t1;
    string str = await t2;  // waits for asyncCall1() to complete

    Im Allgemeinen awaitergibt die Ausführung den äußeren Kontext, von dem aus der aktuelle Kontext aufgerufen wird. Wenn jedoch der äußere Kontext selbst auf den Strom wartet, ist es wie ein sequenzielles awaits im selben Kontext.

Um die asyncVorteile zu nutzen, muss die Anwendung so konzipiert werden, dass sie mehrere parallele Kontexte (Benutzeroberfläche, Datenclient usw.) ausführt. awaitIn einem Kontext werden dann andere Kontexte ausgeführt, sodass die gesamte Anwendung nicht einzelne Kontexte blockiert await.

übersynchronisiert
quelle