[英]How to maintain Thread context across async await model in C#?
每次等待完成“一个选项”时是否使用 ThreadStatic 并设置上下文? 还有其他方法吗?
public async void Test()
{
// This is in Thread 1
Foo foo = new Foo();
Context.context = "context1"; // This is ThreadStatic
string result = await foo.CallAsynx();
// This is most likely Thread 2
Context.context = "context1"; // This might be a different thread and so resetting context
}
如果我不想使用 ThreadStatic,现在还有另一种方法吗?
ThreadStatic
、 ThreadLocal<T>
、线程数据槽和CallContext.GetData
/ CallContext.SetData
不适用于async
,因为它们是特定于线程的。
最好的选择是:
this
作为参数隐式传递); 或者你可以让你的 lambdas 捕获变量(在下面,编译器将通过this
作为参数隐式传递)。HttpContext.Items
(如果您使用的是 ASP.NET 4.5)。CallContext.LogicalGetData
/ CallContext.LogicalSetData
作为 @Noseratio 建议。 您只能在逻辑线程上下文中存储不可变数据; 并且它仅适用于 .NET 4.5,并非适用于所有平台(例如,Win8)。AsyncContext
,强制所有async
延续回到同一线程。只是如果有人在几年后有同样的问题并发现这个线程......
有一个新功能叫做
AsyncLocal<T>
https://docs.microsoft.com/en-us/dotnet/api/system.threading.asynclocal-1?view=netcore-3.1
这适用于“异步/等待”,也适用于:
我只是用以下代码测试这三个:
private void StartTests() {
Thread.Sleep(1000);
Task.Run(() => DoWork1());
Task.Run(() => DoWork2());
}
private void DoWork1() {
ThreadContext.Context.Value = "Work 1";
Thread.Sleep(5);
Task.Run(() => PrintContext("1"));
Thread.Sleep(10);
Dispatcher.BeginInvoke(new Action(() => PrintContext("1")));
Thread.Sleep(15);
var t = new Thread(() => PrintContextT("1"));
t.Start();
}
private void DoWork2() {
ThreadContext.Context.Value = "Work 2";
Task.Run(() => PrintContext("2"));
Thread.Sleep(10);
Dispatcher.BeginInvoke(new Action(() => PrintContext("2")));
Thread.Sleep(10);
var t = new Thread(() => PrintContextT("2"));
t.Start();
}
private void PrintContext(string c) {
var context = ThreadContext.Context.Value;
Console.WriteLine("P: " + context + "-" + c);
Task.Run(() => PrintContext2(c));
}
private void PrintContext2(string c) {
Thread.Sleep(7);
var context = ThreadContext.Context.Value;
Console.WriteLine("P2: " + context + "-" + c);
}
private void PrintContextT(string c) {
var context = ThreadContext.Context.Value;
Console.WriteLine("T: " + context + "-" + c);
}
public class ThreadContext {
public static AsyncLocal<object> Context = new AsyncLocal<object>();
}
输出:
P: 作品 2-2
P: 工作 1-1
P2:工作 2-2
P: 作品 2-2
P2:工作 1-1
P: 工作 1-1
P2:工作 2-2
T: 工作 2-2
P2:工作 1-1
T: 工作 1-1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.