我正在尝试删除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
的任务并行库答案 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))
这应该会提高性能,如果需要更多帮助,我们需要更深入地了解您的代码。