use*_*604 -3 c# parallel-processing multithreading
好的,所以我有一个工作正常的程序.在其中有一个可以并行化的for循环.所以我曾经Parallel.For这样做过.它运行了一两次,但其他时候有以下异常:
未指定的错误发生了一个或多个错误
没有进一步的信息,只有这个有用的信息 任何人都知道可能会发生什么?
编辑:好的,所以我把它钉在一个超出范围的例外.事实证明我在初始化之前访问了数组元素,这似乎是竞争条件.我有这个:
Parallel.For(0, 4, (i, state) =>
{
levelTwoPermutationObjects.Add(new permutationObject());
levelTwoPermutationObjects[i].element = number;
levelTwoPermutationObjects[i].DoThings();
});
Run Code Online (Sandbox Code Playgroud)
这使第二和第三行访问一个显然尚不存在的元素.我将元素初始化程序移出并行循环(以便在访问之前初始化数组),现在它可以正常工作.
迭代几乎是彼此独立的,除了Add()部分,显然依赖于它之前是否有另一个元素.
我在黑暗中冒着风险:levelTwoPermutationObjects不是线程安全的(即是a List<T>).您应该使用的命名空间的集合System.Collections.Generic.Concurrent,如ConcurrentBag<T>(因为是没有线程安全版本List<T>),因为你是痛苦的竞争条件(请参阅这里的例子)与.Add-call(读不写操作是多线程内OK):
public void Add(T item) {
if (_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size++] = item;
_version++;
}
Run Code Online (Sandbox Code Playgroud)
另请参阅MSDN上的评论:
在List上执行多个读取操作是安全的,但如果在读取集合时修改了集合,则可能会出现问题.要确保线程安全,请在读取或写入操作期间锁定集合.要使多个线程可以访问集合以进行读写,您必须实现自己的同步.对于具有内置同步的集合,请参阅System.Collections.Concurrent命名空间中的类.有关本质上线程安全的替代方法,请参阅ImmutableList类.
如果您不愿意或无法适应levelTwoPermutationObjects您的类型,您也可以使用lock类似的危险(危险请勿使用 - 仅用于演示):
var @lock = new object();
Parallel.For(0, 4, (i, state) =>
{
lock (@lock)
{
levelTwoPermutationObjects.Add(new permutationObject());
levelTwoPermutationObjects[i].element = number;
levelTwoPermutationObjects[i].DoThings();
}
});
Run Code Online (Sandbox Code Playgroud)
但这会使Parallel.For-call无用.事实上你应该调整你的代码(如果我正确地解释你的代码):
var @lock = new object();
Parallel.For(0, 4, (i, state) =>
{
var permutationObject = new permutationObject
{
element = number
};
permutationObject.DoThings();
lock (@lock)
{
levelTwoPermutationObjects.Add(permutationObject);
}
});
Run Code Online (Sandbox Code Playgroud)
如果.DoThings()的permutationObject是一个长期运行的操作,你应该火了,忘记带如通话Task.Run,而不是等待结果与进行.Add-call.
否则,您可以将处理链转换为一个种子处理过程,该处理过程将元素添加到集合中(应该是一个短的运行操作)和一个处理过程(每次迭代可以是一个长时间运行的操作),以避免仅由Race条件在顺序写入之后执行读取,例如:
var levelTwoPermutationObjects = Enumerable.Range(0, 4)
.Select(arg => new permutationObject
{
element = number
})
.ToList();
Parallel.ForEach(levelTwoPermutationObjects,
permutationObject => permutationObject.DoThings());
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
82 次 |
| 最近记录: |