使用TPL时如何管理线程本地存储(TLS)?

问题描述 投票:0回答:3

我想在 TLS 中存储日志记录上下文信息,以便我可以在入口点设置一个值,并使该值在所有结果堆栈中可用。这工作得很好,但我也使用 TPL 和 ThreadPool。那么问题就变成了如何将 TLS 数据迁移到其他线程。我可以自己完成这一切,但是我会失去像 Parallel.For 这样的好方法。

使用 TPL 时是否有某种方法可以复制 TLS?当 C# 获得等待功能时,这也适用于它。

谢谢, 埃里克

.net asynchronous threadpool task-parallel-library thread-local-storage
3个回答
5
投票

通常,这是通过使用已提供线程本地数据的 Parallel.For 的重载来处理的。

此重载允许您提供初始化和终结委托,这实际上成为线程本地数据的每个线程的初始化,以及最后的缩减函数以将结果“合并”在一起(每个线程运行一次)。 我在这里详细写了这一点

基本形式是执行以下操作:

object sync = new object();
double result = 0;

Parallel.For(0, collection.Count, 
    // Initialize thread local data:
    () => new MyThreadSpecificData(),
    // Process each item
    (i, pls, currentThreadLocalData) => 
    {
        // Generate a NEW version of your local state data
        MyThreadSpecificData newResults = ProcessItem(collection, i, currentThreadLocalData);
        return newResults;
    },
    // Aggregate results
    threadLocalData =>
    {
       // This requires synchronization, as it happens once per thread, 
       // but potentially simultaneously
       lock(sync)
          result += threadLocalData.Results;
    });

4
投票

我找到了另一种不需要代码的问题解决方案。我能够使用 CallContext 将数据附加到“逻辑线程”。该数据从起始线程传输到 TPL 以及线程池生成的线程。

http://www.wintellect.com/CS/blogs/jeffreyr/archive/2010/09/27/tical-call-context-flowing-data-across-threads-appdomains-and-processes.aspx


0
投票

当然,还有另一种选择:像我们一样编写一个 TaskLocal(T) 类,该类将存储基于当前任务,而不是当前线程。老实说,我不知道为什么 Microsoft 没有将其作为其初始任务实现的一部分。

重要的实现注意事项:因为调用await的任务代码可以被拆分,并恢复为不同的TaskId,所以您还需要做我们也做过的事情,并在TaskLocal(T)中实现一个方法,将新的TaskId映射到以前的TaskId ,然后在任务开始时保存原始TaskId,并在每次await调用后映射它。

© www.soinside.com 2019 - 2024. All rights reserved.