如何在TPL任务中使用像ThreadStatic
这样的东西?我的理解(“使用C#进行Wrox Professional Parallel Programming”,第74页)是一个Task可以在执行期间从一个线程切换到另一个线程。
我想做什么?
我想在静态类中维护会话ID,所以我不需要将此id传递给我的所有方法。我的库有login(id)
,logout(id)
等方法,以及许多与此ID相关联的凭据进行操作的方法。但我不想将此id传递给每个方法。我可以确保在不同的线程中为不同的会话调用我的库。因此,将login()
变量放在ThreadStatic
变量中可以正常工作。
现在我想使用ThreadPool
为我创建的TPL任务。我可以将会话ID传递给Task,但是如果我将这个id存储在ThreadStatic
变量中,那么如果我的Task切换线程,它将无法生存。
答案 0 :(得分:4)
TPL和.Net 4.5的异步流ExecutionContext
,这意味着您可以使用CallContext.LogicalSetData(string, object)
和CallContext.GetLogicalData(string)
,就像使用ThreadStatic
一样}。然而,它确实会导致严重的性能损失。
请参阅Async Causality Chain Tracking,How to include own data in ExecutionContext和ExecutionContext vs SynchronizationContext进行更深入的潜水。
使用示例:
class Program
{
static void Main(string[] args)
{
Logger.Current = new Logger("Test Printer");
Logger.Current.Print("hello from main");
var t1 = Task.Run(() => { Logger.Current.Print("hello from thread " + Thread.CurrentThread.ManagedThreadId); });
var t2 = Task.Run(() => { Logger.Current.Print("hello from thread " + Thread.CurrentThread.ManagedThreadId); });
Task.WaitAll(t1, t2);
}
}
class Logger
{
private string LogName;
public Logger(string logName)
{
if (logName == null)
throw new InvalidOperationException();
this.LogName = logName;
}
public void Print(string text)
{
Console.WriteLine(LogName + ": " + text);
}
public static Logger Current
{
get
{
return CallContext.LogicalGetData("PrinterName") as Logger;
}
set
{
CallContext.LogicalSetData("PrinterName", value);
}
}
}
打印:
Test Printer: hello from main Test Printer: hello from thread 11 Test Printer: hello from thread 10
答案 1 :(得分:2)
我会说避免线程静态,除非你能确定哪些任务在哪些线程上运行。只是通过它。你的意图会更清楚。
答案 2 :(得分:1)
你是对的,线程静态不适合任务。
通过传递参数更好地克服您的问题。通过它会更加清晰和清洁。一点点打字会让你获得更多的可读性和线程安全性。