ThreadStatic for TPL Task

Ger*_*ard 14 .net c# multithreading

如何ThreadStatic在TPL任务中使用?我的理解("使用C#进行Wrox Professional Parallel Programming",第74页)是一个Task可以在执行期间从一个线程切换到另一个线程.

我想做的事?

我想在静态类中维护一个会话ID,所以我不需要将这个id传递给我的所有方法.我的库有类似的方法login(id),logout(id)以及许多与此id相关的凭证进行操作的方法.但我不想将此id传递给每个方法.我可以确保在不同的线程中为不同的会话调用我的库.因此,将id保存login()ThreadStatic变量中将起作用.

现在我想使用由我创建的TPL任务ThreadPool.我可以将我的会话ID传递给Task,但是如果我将这个id存储在ThreadStatic变量中,那么如果我的Task切换线程,它将无法生存.

Mit*_*tch 5

TPL和.NET 4.5的异步流动ExecutionContext,这意味着你可以用CallContext.LogicalSetData(string, object)CallContext.GetLogicalData(string)在大致相同的方式,你会使用ThreadStatic。但是,它确实会导致显着的性能损失。这已被暴露在.net 4.6和最多(包括.Net标准1.3及以上)用AsyncLocal<>包装

请参阅异步因果链跟踪如何在 ExecutionContext 中包含自己的数据以及ExecutionContext 与 SynchronizationContext以获得更深入的了解。

使用示例:

class Program
{
    static async void Main(string[] args)
    {
        Logger.Current = new Logger("Test Printer");

        Logger.Current.Print("hello from main");
        await Task.Run(() => Logger.Current.Print($"hello from thread {Thread.CurrentThread.ManagedThreadId}"));
        await Task.Run(() => Logger.Current.Print($"hello from thread {Thread.CurrentThread.ManagedThreadId}"));
    }
}

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);
    }

    private static AsyncLocal<Logger> _logger = new AsyncLocal<Logger>();
    public static Logger Current
    {
        get => _logger.Value;
        set => _logger.Value = value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

印刷:

测试打印机:来自主的你好  
测试打印机:来自线程 11 的你好 
测试打印机:来自线程 10 的你好