C # async / Abwarten mit ConfigureAwait (false)

8

Basierend auf zahlreichen Büchern und Blogs einschließlich dieses ausgezeichnete hier Es ist klar, dass wenn man eine DLL-Bibliothek schreibt, die Helper-Async-Methoden, dh die Wrapper-Methoden, ausgibt, wird es allgemein als eine Best Practice angesehen, die I / O-Aufgabe von tatsächlichen Async-Methoden intern in einem Thread-Thread wie folgt abzuschließen (Pseudocode unten gezeigt) der Kürze halber und ich verwende HttpClient als Beispiel)

%Vor%

Der Schlüssel hier ist die Verwendung von ConfigureAwait(false) , so dass die IO-Task-Vervollständigung in einem Threadpool-Thread statt im ursprünglichen Threadkontext auftritt, wodurch möglicherweise Deadlocks verhindert werden.

Meine Frage ist aus der Sicht eines Anrufers. Ich bin besonders an einem Szenario interessiert, in dem es Methodenaufrufe zwischen dem Aufrufer und dem obigen Methodenaufruf gibt, wie das folgende Beispiel zeigt.

%Vor%

Reicht es, ConfigureAwait(false) nur für die finale Methode zu haben oder sollte man auch sicherstellen, dass Method1Async und Method2Async ihre asynchronen Methoden intern auch mit ConfigureAwait(false) aufrufen? Es erscheint albern, sie in all diese Zwischenmethoden einzubeziehen, insbesondere wenn Method1Async und Method2Async einfach Überladungen sind, die am Ende MyMethodAsync aufrufen. Irgendwelche Gedanken, bitte erleuchte uns!

Mit Beispiel aktualisiert Also, wenn ich eine Bibliothek mit der folgenden privaten asynchronen Methode habe,

%Vor%

sollte ich sicherstellen, dass die folgenden öffentlich überladenen Methoden ConfigureAwait (false) enthalten, wie unten gezeigt?

%Vor%     
SamDevx 28.02.2015, 00:03
quelle

2 Antworten

9

Definitiv nicht. ConfigureAwait genau wie es der Name andeutet, konfiguriert await . Es wirkt sich nur auf das await aus, das damit verbunden ist.

ConfigureAwait gibt tatsächlich einen anderen erwarteten Typ zurück, ConfiguredTaskAwaitable anstelle von Task , der wiederum einen anderen Erwartertyp ConfiguredTaskAwaiter anstelle von TaskAwaiter

zurückgibt

Wenn Sie die SynchronizationContext für alle Ihre await s ignorieren möchten, müssen Sie ConfigureAwait(false) für jede von ihnen verwenden.

Wenn Sie die Verwendung von ConfigureAwait(false) einschränken möchten, können Sie mein NoSynchronizationContextScope (siehe hier ) verwenden Ganz oben:

%Vor%     
i3arnon 28.02.2015, 00:11
quelle
4

Wenn die Aufgabe erwartet wird, erstellt sie eine entsprechende TaskAwaiter , um die Aufgabe zu verfolgen, die auch die aktuelle SynchronizationContext erfasst. Nachdem die Aufgabe abgeschlossen ist, führt der Erwartete den Code nach dem Warten (genannt die Fortsetzung) für diesen erfassten Kontext aus.

Sie können das verhindern, indem Sie ConfigureAwait(false) aufrufen, was eine andere Art von unbrauchbarem ( ConfiguredTaskAwaitable ) und dessen entsprechenden Vorwarner ( ConfiguredTaskAwaitable.ConfiguredTaskAwaiter ) erzeugt, der die Fortsetzung des erfassten Kontexts nicht ausführt.

Der Punkt ist, dass für jede await eine andere Instanz einesAwarers erstellt wird, es ist nicht etwas, das zwischen allen Erwartungswerten in der Methodeoder dem Programm geteilt wird. Es empfiehlt sich also, ConfigureAwait(false) für jede await -Anweisung aufzurufen.

Sie können den Quellcode für die hier sehen.

    
Ned Stoyanov 28.02.2015 00:15
quelle