ThreadStatic for TPL Task
如何在TPL任务中使用类似ThreadStatic
东西? 我的理解(“使用C#进行Wrox Professional Parallel Programming”,第74页)是一个Task可以在执行期间从一个线程切换到另一个线程。
我想做的事?
我想在静态类中维护一个会话ID,所以我不需要将这个id传递给我的所有方法。 我的库有像login(id)
, logout(id)
方法,以及许多与这个id相关的凭证进行操作的方法。 但我不想将此id传递给每个方法。 我可以确保在不同的线程中为不同的会话调用我的库。 因此,在ThreadStatic
变量中保存login()
内的id将起作用。
现在我想使用ThreadPool
为我创建的TPL任务。 我可以将会话ID传递给Task,但是如果我将这个id存储在ThreadStatic
变量中,那么如果我的Task切换线程,它将无法生存。
TPL和.Net 4.5的异步流程是ExecutionContext
,这意味着您可以使用CallContext.LogicalSetData(string, object)
和CallContext.GetLogicalData(string)
,就像使用ThreadStatic
。 然而,它确实会导致严重的性能损失。
请参阅Async Causality Chain Tracking , 如何在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); } } }
打印:
测试打印机:你好 测试打印机:问题来自11号线 测试打印机:你好,来自主题10
我会说避免线程静态,除非你能确定哪些任务在哪些线程上运行。 只是通过它。 你的意图会更清楚。
你是对的,线程静态不适合任务。
通过传递参数更好地克服您的问题。 通过它会更清晰,更清洁。 一点点打字会让你获得更多的可读性和线程安全性。