Wie funktioniert die async / await Callchain?

8

Ich hatte kürzlich eine Situation, in der ich einen ASP.NET-WebAPI-Controller hatte, der innerhalb seiner Aktionsmethode zwei Webanforderungen an einen anderen REST-Service ausführen musste. Ich hatte meinen Code geschrieben, um die Funktionalität sauber in separate Methoden zu trennen, die ein wenig wie dieses Beispiel aussahen:

%Vor%

Da ich HttpClient verwendet habe, mussten alle Web-Anfragen asynchron sein. Ich habe noch nie Async / Abwarten verwendet, also fing ich an, naiv die Keywords hinzuzufügen. Zuerst habe ich das async Schlüsselwort zur PerformWebRequest(string api) Methode hinzugefügt, aber der Aufrufer hat sich darüber beschwert, dass die PerformWebRequests() Methode auch async sein muss, um await zu verwenden. Also habe ich async gemacht, aber jetzt muss der Aufrufer dieser Methode auch async sein und so weiter.

Was ich wissen möchte, ist, wie weit unten im Kaninchenloch alles markiert sein muss, um einfach zu arbeiten? Sicher würde es einen Punkt geben, an dem etwas synchron laufen muss, wie wird das dann sicher gehandhabt? Ich habe bereits gelesen, dass der Aufruf von async eine schlechte Idee ist, weil es Deadlocks verursachen könnte.

    
Peter Monks 28.08.2014, 16:27
quelle

2 Antworten

13
  

Was ich wissen will, ist, wie tief das Kaninchenloch alles sein muss   async markiert, um einfach zu arbeiten? Sicher würde es einen Punkt geben, wo   etwas muss synchron laufen

Nein, es sollte keinen Punkt geben, an dem etwas synchron läuft, und darum geht es bei Async. Der Ausdruck "async all the way" bedeutet eigentlich den ganzen Weg bis zum Aufruf-Stack.

Wenn Sie eine Nachricht asynchron verarbeiten, lassen Sie Ihre Nachrichtenschleife Anfragen verarbeiten, während Ihre wirklich asynchrone Methode ausgeführt wird, da Sie, wenn Sie tief in das Rabit-Loch gehen, Es gibt keinen Thread .

Wenn Sie beispielsweise eine asynchrone Schaltfläche haben, klicken Sie auf den Ereignishandler:

%Vor%

Wenn die Schaltfläche angeklickt wird, läuft synchron bis zum ersten await . Einmal getroffen, gibt die Methode die Kontrolle an den Aufrufer zurück, was bedeutet, dass der Button-Event-Handler den UI-Thread freigibt, wodurch die Nachrichtenschleife freigegeben wird, um in der Zwischenzeit weitere Anfragen zu verarbeiten.

Dasselbe gilt für Ihre Verwendung von HttpClient . Zum Beispiel, wenn Sie:

%Vor%

Sehen Sie, wie das async -Schlüsselwort bis zur Hauptmethode, die die POST -Anfrage verarbeitet, gestiegen ist. Während die asynchrone HTTP-Anforderung vom Netzwerkgerätetreiber verarbeitet wird, kehrt der Thread zum ASP.NET ThreadPool zurück und kann zwischenzeitlich weitere Anforderungen verarbeiten.

Eine Konsolenanwendung ist ein Sonderfall, denn wenn die Main -Methode beendet wird, wird die Anwendung beendet, es sei denn, Sie drehen einen neuen Vordergrund-Thread . Dort müssen Sie sicherstellen, dass, wenn der einzige Aufruf ein Async-Aufruf ist, Sie explizit Task.Wait oder Task.Result verwenden müssen. Aber in diesem Fall ist der Standard SynchronizationContext der ThreadPoolSynchronizationContext , wo es keine Chance gibt, einen Deadlock zu verursachen.

Als Schlussfolgerung sollten asynchrone Methoden nicht synchron oben im Stapel verarbeitet werden , es sei denn, es handelt sich um einen exotischen Anwendungsfall (z. B. eine Konsolenanwendung), sie sollten asynchron den gesamten Weg durchlaufen Lassen Sie den Thread frei, wenn möglich.

    
Yuval Itzchakov 28.08.2014, 17:32
quelle
0

Sie müssen bis zum Anfang des Aufruf-Stacks "async ganz nach oben" gehen, wo Sie eine Nachrichtenschleife erreichen, die alle asynchronen Anfragen verarbeiten kann.

    
Servy 28.08.2014 16:39
quelle