avo*_*avo 4 .net c# task-parallel-library async-await
我注意到我的CallContext.LogicalSetData/LogicalGetData
工作方式并不像我预期的那样.即使没有异步或任何类型的线程切换,async
方法内部设置的值也会被恢复.
这是一个简单的例子:
using System;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
static async Task<int> TestAsync()
{
CallContext.LogicalSetData("valueX", "dataX");
// commented out on purpose
// await Task.FromResult(0);
Console.WriteLine(CallContext.LogicalGetData("valueX"));
return 42;
}
static void Main(string[] args)
{
using(ExecutionContext.SuppressFlow())
{
CallContext.LogicalSetData("valueX", "dataXX");
Console.WriteLine(CallContext.LogicalGetData("valueX"));
Console.WriteLine(TestAsync().Result);
Console.WriteLine(CallContext.LogicalGetData("valueX"));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
它产生这个输出:
dataXX dataX 42 dataXX
如果我进行TestAsync
非异步,它按预期工作:
static Task<int> TestAsync()
{
CallContext.LogicalSetData("valueX", "dataX");
Console.WriteLine(CallContext.LogicalGetData("valueX"));
return Task.FromResult(42);
}
Run Code Online (Sandbox Code Playgroud)
输出:
dataXX dataX 42 dataX
如果我内部有一些真正的异步TestAsync
,我会理解这种行为,但事实并非如此.我甚至使用ExecutionContext.SuppressFlow
,但这并没有改变任何东西.
有人可以解释为什么它这样工作?
在这种情况下,"正如所料"对于不同的人来说是不同的.:)
在最初的Async CTP(没有修改任何框架代码)中,根本不支持"异步 - 本地"类型的上下文.MS修改了LocalCallContext
.NET 4.5以添加此支持.使用异步并发(即Task.WhenAll
)时,旧行为(具有共享逻辑上下文)尤其成问题.
我解释的高层力学LocalCallContext
中async
的方法在我的博客.关键在这里:
当
async
方法启动时,它会通知其逻辑调用上下文以激活写时复制行为.
逻辑调用上下文中有一个特殊的写时复制标志,只要async
方法开始执行,它就会被打开.这是由async
状态机完成的(具体地说,在当前实现中,AsyncMethodBuilderCore.Start
调用ExecutionContext.EstablishCopyOnWriteScope
).而"flag"是一种简化 - 没有实际的布尔成员或任何东西; 它只ExecutionContextBelongsToCurrentScope
是以任何未来写入将(浅)复制逻辑调用上下文的方式修改状态(和朋友).
只要完成方法的同步部分,相同的状态机方法(Start
)就会调用.这就是恢复以前的逻辑环境.ExecutionContextSwitcher.Undo
async
归档时间: |
|
查看次数: |
1786 次 |
最近记录: |