c# - 添加到列表的并行循环

标签 c# .net

是否可以在循环长度增加的情况下并行化循环?

List<int> list = new List<int>() { 0, 1 };

for (int i = 0; i < list.Count; i++)
//Parallel.For(0, list.Count, (i) =>
{
    Console.WriteLine(list[i]);
    if (i == 0) list.Add(2);
}//);

//foreach (int i in list)
//Parallel.ForEach(list, (i) =>
//{
//    Console.WriteLine(i);
//    if (i == 0) list.Add(2);
//}//);

Console.ReadLine();

在这个简单的例子中,预期的输出是:

0
1
2

上面的代码对于序列号“for”可以正常工作,但对于序列号“foreach”却由于集合被修改而失败。对于这两种并行化实现,代码都已完成,但输出缺少最后的“2”。

最佳答案

在 for each 循环中更改集合是无效的。基本上以任何方式修改列表都会使枚举器无效。以下是 IEnumerator 文档中的引述:

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and its behavior is undefined.

有关更多信息,请查看 this post .至于并行实现:

  • Parallel.ForEach - 这与每个标准的 IEnumerator 问题相同
  • Parallel.For - 将循环数作为常量而不是引用传递给 for。这意味着当计数发生变化时,它不会改变循环次数

更安全的模式是在调用并行实现之前添加、删除和修改列表元素。然后线程可以处理这些元素。如果无法做到这一点,则确定循环后将拥有的元素数量,然后使用数组按索引存储/处理这些元素。最后将任何非空值拉回到列表中。这样您就不必担心与列表有关的线程安全问题(Insert 会将其他元素向前推,使您的索引无效)。以下应该有效:

// EX: might be initialized with a call to the database: "COUNT(id)"
int expectedElements = 10;
if (myList.Count < expectedElements)
  for (var idx = myList.Count; idx <= expectedElements; idx++) myList.Add(null);

var elements = myList.ToArray();
System.Threading.Tasks.Parallel.For(0, expectedElements, (idx) =>
{
  // "remove" the element
  if (idx % 3 == 0) elements[idx] = null;

  // "modify" the element
  if (idx % 3 == 1) elements[idx] = DifferentElement(idx);

  // "add" an element
  if (idx % 3 == 2) elements[idx] = GetNewElement(idx);
});

// clear current list, add new elements, remove null values
myList.Clear();
myList.AddRange(elements);
myList.RemoveAll(item => item == null);

现在您可以随心所欲地“添加”、“删除”和“修改”,结果会返回到列表中!

关于c# - 添加到列表的并行循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22713592/

相关文章:

c# - 无法确定外键的复合外键顺序

c# - 使用 LinqToExcel 拉取整个 excel 行

c# - 在Http Post请求中,提交表单和在正文中发送内容有什么区别

c# - 读取 JavaScript 文件并通过 HttpHandler 将其输出回来

c# - 如何在没有 STA 警告的情况下在 MSTest 中使用 WaitHandler.WaitAll?

c# - 查找嵌套和排序

c# - 当使用自定义契约(Contract)解析器而不是 JsonConverter 属性时,自定义 JsonConverter 被忽略以进行反序列化

C#:如何在运行时向对象添加属性?

.net - 如何获取我的进程加载的文件列表?

c# - 如何修复 StdDev 计算中的浮点伪像?