我正在尝试删除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
类不是为并发写(/remove)操作而设计的,如MSDN中所述:
对列表执行多个读取操作是安全的,但是如果在读取集合时对其进行了修改,则可能会出现问题。为确保线程安全,请在读取或写入期间锁定集合活动使集合能够由多个线程访问对于阅读和写作,您必须实现自己的同步。有关具有内置同步的集合,请参阅System.Collections.Concurrent命名空间。对于固有螺纹-安全或者,请参见ImmutableList类。
有关支持并发访问的数据结构,请参阅这篇链接文章。
要澄清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))
这应该会提高性能,为了获得更多帮助,我们需要对您的代码有更多的了解。