任务 Parallel.ForEach 循环删除项目时出错 "Index was outside the bounds of the array. "

Task Parallel.ForEach loop Error when removing items "Index was outside the bounds of the array. "

我正在尝试删除 foreach 循环中通用对象列表的项目。当我对任务并行库循环做同样的事情时,我收到了错误。 索引超出数组范围。

以下是我的代码

List<string> lstSubscriberDidTransaction = ...; // Initialization
var lstSubscriber = JsonConvert.DeserializeObject<List<SubscriberInfoShortenObject>>(somestring);

foreach (string strId in lstSubscriberDidTransaction)
{
    lstSubscriber.RemoveAll(h => h != null && h.Msisdn == strId);
}

//Parallel.ForEach(lstSubscriberDidTransaction, msisdn => lstSubscriber.RemoveAll(h => h != null && h.Msisdn == msisdn));

有人可以帮我吗 我正在使用 .net 3.5。对于具有 http://nuget.org/packages/TaskParallelLibrary

的任务并行库

List class 并非为并发写入(/删除)操作而设计,如 MSDN:

中所述

It is safe to perform multiple read operations on a List, but issues can occur if the collection is modified while it’s being read. To ensure thread safety, lock the collection during a read or write operation. To enable a collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization. For collections with built-in synchronization, see the classes in the System.Collections.Concurrent namespace. For an inherently thread–safe alternative, see the ImmutableList class.

有关支持并发访问的数据结构,请参阅this linked article

澄清为什么您的问题来自 List class: RemoveAll 操作将遍历列表实例并将谓词与每个包含的实例进行匹配。如果谓词的计算结果为真,则匹配实例的索引将用于删除该条目。如果该操作是在并发事务中执行的,则另一个线程可能已经删除了另一个条目,因此该索引不再有效或将指向另一个与谓词不匹配的实例。因此该操作不是线程安全的,不会给出您期望的结果。 为了您的观看乐趣,给定的代码是 List class:

的反编译方法
public int RemoveAll(Predicate<T> match)
{
  if (match == null)
    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
  int index1 = 0;
  while (index1 < this._size && !match(this._items[index1]))
    ++index1;
  if (index1 >= this._size)
    return 0;
  int index2 = index1 + 1;
  while (index2 < this._size)
  {
    while (index2 < this._size && match(this._items[index2]))
      ++index2;
    if (index2 < this._size)
      this._items[index1++] = this._items[index2++];
  }
  Array.Clear((Array) this._items, index1, this._size - index1);
  int num = this._size - index1;
  this._size = index1;
  ++this._version;
  return num;
}

给你更多提示: 不要使用并行代码,因为如果不进行大的更改,它对您没有帮助。优化您的查找数据结构并简化您的语句。

HashSet<string> lstSubscriberDidTransaction = ...
...

lstSubscriber.RemoveAll(h => h != null && lstSubscriberDidTransaction.Contains(h.Msisdn))

这应该会提高性能,要获得更多帮助,我们需要更深入地了解您的代码。