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.
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:
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.
Tags und Links .net c# task-parallel-library async-await asynchronous