我对C#中的Parallel.Foreach有疑问。我是多线程的新手,并且从一个月开始学习它。我正在使用Foreach循环,在该foreach循环中,我找到整数列表的平均值,并将每个平均值添加到一个cuncurrent包中。但是我面临的问题并不是所有迭代的结果都会被添加。我的列表中有10个条目,但是我添加的cuncurrent包在foreach循环结束时的条目少于10个。任何人都可以让我知道我做错了什么。
以下是我的代码:
static void Main(string[] args)
{
List<List<int>> intList = new List<List<int>>();
List<int> ints = new List<int>();
Random rand = new Random();
for (int k = 1; k <= 10; k ++)
{
ints.Clear();
for (int i = 0; i < 10000000; i++)
{
ints.Add(rand.Next(10000000));
}
List<int> copy = new List<int>(ints);
intList.Add(copy);
}
ConcurrentBag<double> results = new ConcurrentBag<double>();
Parallel.ForEach<List<int>, double>(intList,
() => 0,
(eachIterationList, pls, threadLocal) =>
{
threadLocal = eachIterationList.Average();
return threadLocal;
},
(result) =>
{
lock (results)
{
results.Add(result);
}
});
Console.WriteLine("No of results in results variable: {0}", results.Count);
Console.ReadLine();
}
结果变量在写入控制台时包含的元素少于10个我认为应该具有的元素。
答案 0 :(得分:0)
为什么要锁定结果ConcurrentBag?做这样简单的工作:
Parallel.ForEach(intList,
list =>
{
results.Add(list.Average());
});
锁定结果并不能保证您的商品顺序正确。 如果您希望两者都是同步的,请改用:
List<double> results = new List<double>(Enumerable.Repeat(0.0d, intList.Count));
Parallel.For(0, intList.Count,
(i) =>
{
results[i] = intList[i].Average();
});
或使用.ForEach():
List<double> results = new List<double>(Enumerable.Repeat(0.0d, intList.Count));
Parallel.ForEach(intList,
(item, loop, i) =>
{
results[(int)i] = item.Average();
});
答案 1 :(得分:0)
您可以看到本地最终委托在每个用于处理Parallel.ForEach
的任务的最终操作上运行。每次都可以是不同的数字。因此,如果您修改下面列出的代码,您将看到用于列表迭代的任务数与执行最终操作的任务数相同。最终授权代表的用途与您的需要不同。
您需要了解.NET中的线程和任务之间的区别。 当你使用lock添加到ConcurrentBag时你的代码也是错误的,因为它已经支持多线程添加到集合而你不需要锁定。
List<List<int>> intList = new List<List<int>>();
List<int> ints = new List<int>();
Random rand = new Random();
for (int k = 1; k <= 10; k++)
{
ints.Clear();
for (int i = 0; i < 10000000; i++)
{
ints.Add(rand.Next(10000000));
}
List<int> copy = new List<int>(ints);
intList.Add(copy);
}
HashSet<int?> resultTaskIds = new HashSet<int?>();
HashSet<int?> iterationTaskIds = new HashSet<int?>();
ConcurrentBag<double> results = new ConcurrentBag<double>();
Parallel.ForEach<List<int>, double>(intList,
() => 0,
(eachIterationList, pls, threadLocal) =>
{
iterationTaskIds.Add(Task.CurrentId);
return eachIterationList.Average();
},
(result) =>
{
resultTaskIds.Add(Task.CurrentId);
results.Add(result);
});