问题描述
使用 C# 中的新 async/await 关键字,现在会影响您使用 ThreadStatic 数据的方式(和时间),因为回调委托在与 async
不同的线程上执行操作开始.例如,以下简单的控制台应用程序:
With the new async/await keywords in C#, there are now impacts to the way (and when) you use ThreadStatic data, because the callback delegate is executed on a different thread to one the async
operation started on. For instance, the following simple Console app:
[ThreadStatic]
private static string Secret;
static void Main(string[] args)
{
Start().Wait();
Console.ReadKey();
}
private static async Task Start()
{
Secret = "moo moo";
Console.WriteLine("Started on thread [{0}]", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Secret is [{0}]", Secret);
await Sleepy();
Console.WriteLine("Finished on thread [{0}]", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Secret is [{0}]", Secret);
}
private static async Task Sleepy()
{
Console.WriteLine("Was on thread [{0}]", Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
Console.WriteLine("Now on thread [{0}]", Thread.CurrentThread.ManagedThreadId);
}
将输出如下内容:
Started on thread [9]
Secret is [moo moo]
Was on thread [9]
Now on thread [11]
Finished on thread [11]
Secret is []
我也尝试过使用 CallContext.SetData
和 CallContext.GetData
并得到相同的行为.
I've also experimented with using CallContext.SetData
and CallContext.GetData
and got the same behaviour.
在阅读了一些相关的问题和线程后:
After reading some related questions and threads:
- CallContext vs ThreadStatic
- http://forum.springframework.net/showthread.php?572-CallContext-vs-ThreadStatic-vs-HttpContext&highlight=LogicalThreadContext
- http://piers7.blogspot.co.uk/2005/11/threadstatic-callcontext-and_02.html
似乎像 ASP.Net 这样的框架显式地跨线程迁移 HttpContext,而不是 CallContext
,因此使用 async
可能会发生同样的事情和 await
关键字?
it seems that frameworks like ASP.Net explicitly migrates the HttpContext across threads, but not the CallContext
, so perhaps the same thing is happening here with the use of async
and await
keywords?
考虑到 async/await 关键字的使用,存储与可以(自动!)在回调线程上恢复的特定执行线程关联的数据的最佳方式是什么?
With the use of the async/await keywords in mind, what's the best way to store data associated with a particular thread of execution that can be (automatically!) restored on the callback thread?
谢谢,
推荐答案
你可以使用 CallContext.LogicalSetData
和 CallContext.LogicalGetData
,但是我建议您不要这样做,因为当您使用简单的并行性 (Task.WhenAny
/Task.WhenAll
) 时,它们不支持任何类型的克隆".
You could use CallContext.LogicalSetData
and CallContext.LogicalGetData
, but I recommend you don't because they don't support any kind of "cloning" when you use simple parallelism (Task.WhenAny
/ Task.WhenAll
).
我打开了一个 UserVoice请求获得更完整的 async
兼容上下文",在 一篇 MSDN 论坛帖子.似乎不可能自己建造一个.Jon Skeet 有一个不错的博客条目 关于这个主题.
I opened a UserVoice request for a more complete async
-compatible "context", explained in more detail in an MSDN forum post. It does not seem possible to build one ourselves. Jon Skeet has a good blog entry on the subject.
因此,我建议您使用参数、lambda 闭包或本地实例的成员 (this
),如 Marc 所述.
So, I recommend you use argument, lambda closures, or the members of the local instance (this
), as Marc described.
是的,OperationContext.Current
没有在 await
s 中保留.
And yes, OperationContext.Current
is not preserved across await
s.
更新: .NET 4.5 确实支持 async
代码中的 Logical[Get|Set]Data
.详情在我的博客上.
Update: .NET 4.5 does support Logical[Get|Set]Data
in async
code. Details on my blog.
这篇关于使用带有 async/await 的 ThreadStatic 变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!