有没有办法在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 ParallelOptions{MaxDegreeOfParallelism = 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
中找到它答案 0 :(得分:5)
ThreadID由底层环境分配,并且不保证从0到[线程数],或者从运行到运行都保持一致。
只有少数与threadID有关的合同,即使这些也没有保证:
答案 1 :(得分:5)
由于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 :(得分:0)
您几乎总会得到一个大于一的线程ID。并行操作将在线程池线程上进行调度。由于这些线程是在应用程序启动后创建的,因此线程ID已经启动。
答案 3 :(得分:0)
var data = new[] { 0,0,0,0,0,0,0,0,0,0,0,0,0};
Parallel.ForEach(data, new ParallelOptions{MaxDegreeOfParallelism = 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(这是您的另一个假设)。
答案 4 :(得分:0)
由于这在 .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
});