在 parallel.ForEach 循环中获取线程 ID
Posted
技术标签:
【中文标题】在 parallel.ForEach 循环中获取线程 ID【英文标题】:Get a thread id inside parallel.ForEach loop 【发布时间】:2015-11-22 02:29:19 【问题描述】:有没有办法在 Parallel.FoEach 循环中找到线程 ID。我尝试使用 var threadId = Thread.CurrentThread.ManagedThreadId - 1;
,但它没有为我提供我正在寻找的正确索引。
这是一个简单的例子:
private void TestProgram()
int numThreads = 1;
var values = new List<float>();
for (int i = 0; i < numThreads; ++i)
values.Add(i);
var data = new List<int>();
for (int i = 0; i < numThreads; ++i)
data.Add(i);
Parallel.ForEach(data, new ParallelOptionsMaxDegreeOfParallelism = numThreads, i =>
//foreach (var i in data)
var threadId = Thread.CurrentThread.ManagedThreadId - 1; // make the index to start from 0
values[threadId] += i;
);
即使设置了MaxDegreeOfParallelism to 1
,我仍然得到threadId
大于1。
在上述场景中,有没有办法在 Parallel.ForEach 中找到线程 ID?
注意:我可以在我使用的示例中使用 Parallel.For。但我的问题是在 Parallel.ForEach 中找到它
【问题讨论】:
How to know threadid for each thread spawn by parallel.foreach的可能重复 Parallel.Foreach 是并行任务库的一部分。试试 Task.CurrentId 看看它的行为如何。 【参考方案1】:由于 Parallel.ForEach 是任务库的一部分,Task.CurrentId 将使您更接近您正在寻找的内容:
var data = new[] 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ;
Parallel.ForEach(data, new ParallelOptions MaxDegreeOfParallelism = 4 , i =>
Console.WriteLine(Task.CurrentId);
);
输出为 1 1 1 1 1 1 1 1 1 1 2 2 1
但是,文档中有免责声明:
任务 ID 是按需分配的,不一定代表 创建任务实例的顺序。请注意,虽然 冲突非常罕见,任务标识符不保证是 独一无二。
【讨论】:
【参考方案2】:ThreadID 由底层环境分配,不保证从 0 到 [线程数] 甚至每次运行都一致。
只有少数几个关于 threadID 的合同,甚至这些合同也不能保证:
你不会得到 ThreadID 0 ThreadID 1 通常保留给主线程【讨论】:
【参考方案3】:您几乎总是会得到一个大于 1 的线程 ID。并行操作将安排在线程池线程上。由于这些线程是在应用程序启动后创建的,因此线程 ID 应该已经启动。
【讨论】:
【参考方案4】:var data = new[] 0,0,0,0,0,0,0,0,0,0,0,0,0;
Parallel.ForEach(data, new ParallelOptionsMaxDegreeOfParallelism = 10, i =>
Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId);
);
我得到输出:
180 180 180 180 180 180 180 180 62 62 62 62 180
这是典型的。这是一个环境 ID,与您的 foreach 循环几乎没有关系。您还可以看到,在这种情况下,.NET 不需要达到 MaxDegreeOfParallelism(这是您的另一个假设)。
【讨论】:
【参考方案5】:由于这在 .NET 中似乎不可用,只需将看似随机的值映射回从零开始的值。
示例如下,您可以根据需要创建资源,每个线程一个。 'locker' 是为了防止线程相互干扰。另请注意,列表应替换为 System.Collections.Concurrent.ConcurrentBag 等线程安全对象
object locker = new object();
List<int> ids = new List<int>();
List<object> resources = new List<object>();
Parallel.For(0, 20000, x =>
int thread_id = ids.IndexOf(Environment.CurrentManagedThreadId);
if (thread_id == -1)
ids.Add(Environment.CurrentManagedThreadId);
thread_id = ids.IndexOf(Environment.CurrentManagedThreadId);
while (resources.Count < thread_id + 1)
lock (locker)
resources.Add(new object());
object resource = resources[thread_id];
// do stuff with the resource
);
【讨论】:
以上是关于在 parallel.ForEach 循环中获取线程 ID的主要内容,如果未能解决你的问题,请参考以下文章
Parallel.ForEach 具有可枚举的 KeyValuePairs?
我在 Parallel.ForEach 循环中收到 TaskCanceledException,如何解决?
如何正确调用 Parallel.ForEach 循环中的调用异步方法[重复]