Parallel.For多久调用一次localInit?

时间:2018-08-08 13:32:37

标签: .net task-parallel-library parallel.foreach

我一直在尝试Parallel.For。特别是支持线程本地数据的重载,例如

  

公共静态System.Threading.Tasks.ParallelLoopResult For(长fromInclusive,长toExclusive,System.Threading.Tasks.ParallelOptions parallelOptions,Func localInit,Func主体,Action localFinally);

根据documentation

  

为参与循环执行的每个线程调用一次localInit委托

但是我认为下面的例子与之矛盾

var threads = new ConcurrentBag<int>();
ValueTuple LocalInit()
{
    threads.Add(Thread.CurrentThread.ManagedThreadId);
    return new System.ValueTuple();
}
ValueTuple Body(long i, ParallelLoopState _, ValueTuple state) 
{
    Thread.Sleep(100);
    return state;
}
void LocalFinally(ValueTuple state) { };

Parallel.For(0L, 1000L, new ParallelOptions(), LocalInit, Body, LocalFinally);

Console.WriteLine($"{threads.Count} inits between {threads.Distinct().Count()} threads");

它打印一条消息,例如

  

13个线程之间的79个初始化

这是怎么回事?

1 个答案:

答案 0 :(得分:2)

尝试记录任务ID Task.CurrentId而不是线程ID。

var threads = new ConcurrentBag<int>();
var tasks = new ConcurrentBag<int>();
ValueTuple LocalInit()
{
    threads.Add(Thread.CurrentThread.ManagedThreadId);
    tasks.Add(Task.CurrentId ?? throw new Exception());
    return new System.ValueTuple();
}
ValueTuple Body(long i, ParallelLoopState _, ValueTuple state) 
{
    Thread.Sleep(100);
    return state;
}
void LocalFinally(ValueTuple state) { };

Parallel.For(0L, 1000L, new ParallelOptions(), LocalInit, Body, LocalFinally);

Console.WriteLine($"{threads.Count} inits between {threads.Distinct().Count()} threads");
Console.WriteLine($"{tasks.Count} inits between {tasks.Distinct().Count()} tasks");

此打印

  

16个线程之间的87个初始化
  87个任务之间的87个初始化

该文档是错误的。他们应该改为

  

对参与循环执行的每个任务一次调用一次localInit委托

任务可能多于线程。总是线程数任务数迭代数