2017-08-25 14 views
4

await是由編譯器所遇到它變換async方法的狀態機和繼續經由AsyncTaskMethodBuilder AwaitUnsafeOnCompleted VS AwaitOnCompleted上AWAIT

AsyncTaskMethodBuilder.AwaitUnsafeOnCompleted調度所概述hereAsyncTaskMethodBuilder.AwaitOnCompleted所概述here

翻翻.NET源hereAsyncTaskMethodBuilder.AwaitUnsafeOnCompleted電話Awaiter.UnSafeOnCompleted

看來Awaiter.UnSafeOnCompleted不流執行上下文(代碼here)。

注意它通過falseflowExecutionContext。這意味着如果我使用LogicalCallContextExecutionContext的一部分)來存儲任何數據(例如activityId),那麼它將不會流入連續路徑,這意味着我無法訪問它。

所以,我的問題是什麼原因導致編譯器選擇Unsafe Completion

Stephen Toub也提到了同樣的事情here但沒有給出任何細節。 「.NET Framework中的所有這些方法都支持異步工作以這種方式捕獲和恢復ExecutionContext(即,除了那些前綴爲」Unsafe「的單詞之外的所有方法都是不安全的,因爲它們顯式不流執行上下文」

回答

2

這意味着,如果我使用LogicalCallContext [...]存儲任何數據[...]那麼它不會在連續路徑中流動

不完全是。OnCompleted只是執行上下文流動的一種可能的方式,你需要排除它的其他方式y流動。

所以,我的問題是什麼導致編譯器選擇Unsafe Completion?

只要有可能,編譯器都會使用它(即每當執行ICriticalNotifyCompletion時)。

但是,編譯器也間接依賴於AsyncMethodBuilderCore,這確實會導致執行上下文流經它的MoveNextRunner輔助類。在這種情況下,通過僅存儲對執行上下文的單個引用,而不是每個延續的一個引用,可以更有效地實現它。

除非你想方設法阻止執行上下文流動,否則你不需要擔心。

+1

非常令人印象深刻的答案。據我可以告訴支持「每當'ICriticalNotifyCompletion'實現」的聲明實現細節可以在Roslyn的[AsyncMethodToStateMachineRewriter]中找到(https://github.com/dotnet/roslyn/blob/d4dab355b96955aca5b4b0ebf6282575fad78ba8/src/Compilers/ CSHARP /便攜/放下/ AsyncRewriter/AsyncMethodToStateMachineRewriter.cs) –