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