TPL数据流线程本地数据

时间:2013-02-04 18:50:38

标签: .net task-parallel-library tpl-dataflow thread-local-storage

是否有一种将线程本地数据传递到ActionBlock的好方法,这样如果在其DataFlowExecutionOptions中指定MaxDegreeOfParallelization为> 1,那么执行该操作的每个任务都有自己的线程本地数据?

以下是我的一些代码,可能会澄清我想要做的事情:

var options = new ExecutionDataflowBlockOptions() 
     {
        MaxDegreeOfParallelism = 12
     };

ActionBlock<int> actionBlock = new ActionBlock<int>(PerformAction, options);

List<int> resultsList = new List<int>();

void PerformAction(int i)
{
    // do some work

    // add them to resultsList 

    // i want to make sure that each thread that executes this method has its 
    // own copy of resultsList 
}

我希望能够让ActionBlock调用我提供的线程本地init函数。像这样:

new ActionBlock<int>(PerformAction, options, () => new List<int>()); 

让它将我的线程本地数据传递给我的Action函数:

void PerformAction(int i, List<int> localUserData) {...}

1 个答案:

答案 0 :(得分:2)

我仍然不明白为什么在数据流块中需要线程本地列表。你是对的,TDF对线程局部值没有任何明确的支持(Parallel.ForEach()的方式)。但这并不意味着你不能使用线程局部值,你只需要使用ThreadLocal手动完成所有事情(我认为[ThreadStatic]在这里不会很好用,因为它不会不允许你跟踪所有线程本地实例。例如:

private static ThreadLocal<List<int>> threadLocalList;

private static void Main()
{
    threadLocalList = new ThreadLocal<List<int>>(() => new List<int>(), true);

    var block = new ActionBlock<int>(
        (Action<int>)PerformAction,
        new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 4 });

    for (int i = 0; i < 10; i++)
        block.Post(i);

    block.Complete();
    block.Completion.Wait();

    foreach (var list in threadLocalList.Values)
        Console.WriteLine(string.Join(", ", list));

    threadLocalList.Dispose();
}

private static void PerformAction(int i)
{
    threadLocalList.Value.Add(i * i);
}