2017-08-25 3 views
4

Wenn await vom Compiler angetroffen wird es transformiert die async Methode auf eine Zustandsmaschine und die Fortsetzung überAsyncTaskMethodBuilder AwaitUnsafeOnCompleted vs AwaitOnCompleted auf Await

AsyncTaskMethodBuilder.AwaitUnsafeOnCompletedhereAsyncTaskMethodBuilder.AwaitOnCompleted oder wie skizziert als here umrissenen geplant ist.

Blick durch .NET Quelle here, AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted Anrufe Awaiter.UnSafeOnCompleted

Es scheint, dass Awaiter.UnSafeOnCompleted nicht die ExecutionContext fließt (Code here).

Hinweis es false-flowExecutionContext gibt. Das bedeutet, wenn ich bin mit LogicalCallContext (Teil von ExecutionContext) alle Daten zu speichern (z.B. ActivityID), dann wird es nicht in Fortsetzungspfad geleitet werden, das bedeutet, dass ich nicht darauf zugreifen kann.

Also ist meine Frage , was bewirkt, dass der Compiler unsafe Completion wählt?

Stephen Toub erwähnt auch die gleiche Sache here aber gab keine Details. „Alle Methoden in .NET Framework, die Gabel asynchrone Arbeit erfassen und wiederherstellen ExecutionContext in einer Weise, wie dies (das heißt, alle mit Ausnahme derjenigen, für mit dem Wort voran‚Unsafe‘, die unsicher sind, weil sie explizit nicht fließen ExecutionContext“

Antwort

2

Das bedeutet, wenn ich bin mit LogicalCallContext [...] alle Daten zu speichern, [...], dann wird es nicht in Fortsetzung Weg

Nicht genau geflossen sein. OnCompleted ist nur eine der Möglichkeiten, wie der Ausführungskontext fließen kann: Sie müssen die anderen Möglichkeiten ausschließen, mit denen er ausgeführt werden kann y Fluss.

Also ist meine Frage, was bewirkt, dass der Compiler unsafe Completion wählen?

Der Compiler wird dies wann immer möglich verwenden (d. H. Wann immer ICriticalNotifyCompletion implementiert wird).

Allerdings stützt sich der Compiler auch indirekt auf AsyncMethodBuilderCore, und dies führt dazu, dass der Ausführungskontext über seine Hilfsklasse MoveNextRunner fließt. Dies gelingt in diesem Fall effizienter, da nur eine einzige Referenz auf den Ausführungskontext gespeichert wird und nicht eine Referenz für jede Fortsetzung.

Sofern Sie nicht aus dem Weg gehen den Ausführungskontext fließt zu verhindern, müssen Sie nicht darum kümmern.

+1

Ziemlich beeindruckende Antwort. Soweit ich die blutigen Details der Implementierung kann sagen, die Unterstützung der „wann immer' ICriticalNotifyCompletion' implementiert“Anweisung kann in Roslyn des [AsyncMethodToStateMachineRewriter] zu finden (https://github.com/dotnet/roslyn/blob/d4dab355b96955aca5b4b0ebf6282575fad78ba8/src/Compilers/ CSharp/Portabel/Senken/AsyncRewriter/AsyncMethodToStateMachineRewriter.cs) –