任务Parallel.ForEach循环删除项目时出错#34;索引超出了数组的范围。 "

时间:2015-04-01 07:37:21

标签: c# task-parallel-library

我正在尝试删除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。 for http://nuget.org/packages/TaskParallelLibrary

的任务并行库

1 个答案:

答案 0 :(得分:2)

List类不适用于并发写入(/删除)操作,如MSDN中所述:

  

在List上执行多个读取操作是安全的,但是   如果在读取集合时修改了集合,则可能会出现问题。   为确保线程安全,请在读取或写入期间锁定集合   操作。使多个线程可以访问集合   对于读写,您必须实现自己的同步。   对于具有内置同步的集合,请参阅中的类   System.Collections.Concurrent命名空间。对于固有的线程安全   替代方案,请参阅ImmutableList类。

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

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

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))

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