2017-08-25 15 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) –