问题描述
非常简单的Parallel.ForEach
调用有时会失败,并显示
库中某处而不是我的代码中的对象引用未设置为对象的实例。
exception。这是堆栈跟踪。
at System.Threading.Tasks.TaskReplicator.Run[TState](ReplicatableuserAction`1 action,ParallelOptions options,Boolean stopOnFirstFailure)
at System.Threading.Tasks.Parallel.PartitionerForEachWorker[TSource,TLocal](Partitioner`1 source,ParallelOptions parallelOptions,Action`1 simpleBody,Action`2 bodyWithState,Action`3 bodyWithStateAndindex,Func`4 bodyWithStateAndLocal,Func`5 bodyWithEverything,Func`1 localInit,Action`1 localFinally)
--- End of stack trace from prevIoUs location where exception was thrown ---
at System.Threading.Tasks.Parallel.ThrowSingleCancellationExceptionorOtherException(ICollection exceptions,CancellationToken cancelToken,Exception otherException)
at System.Threading.Tasks.Parallel.PartitionerForEachWorker[TSource,Action`1 localFinally)
at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IEnumerable`1 source,Action`1 body,Action`1 localFinally)
at System.Threading.Tasks.Parallel.ForEach[TSource](IEnumerable`1 source,Action`1 body)
...
这种情况很少发生,我已经看到它只在Linux上的.NET Core 2.1 App上发生过两次,没有明显的原因,也没有再现的方法。
这是我的简化代码:
var chunkSize = 100;
var processingList = new List<int>();
// removed code here which fill the processing list with data. No nulls here for sure
Parallel.ForEach(
ChunkIndexes(processingList.Count,chunkSize),(interval) =>
{
var worker = new MyWorker();
worker.Process(processingList,interval.startIndex,interval.endindex);
});
// Function called by Parallel.ForEach()
public static IEnumerable<(int startIndex,int endindex)> ChunkIndexes(int totalCount,int chunkSize)
{
for (var i = 0; i < totalCount; i += chunkSize)
{
yield return (i,Math.Min(i + chunkSize,totalCount));
}
}
Parallel.ForEach
中的代码在列表的不同部分上工作,并且仅修改值而不以任何方式更改列表大小。
没有异步/等待代码,也没有文件访问权限,也没有网络调用。它看起来非常简单,我只是无法弄清楚它可能由于任何原因而失败。有什么想法吗?
解决方法
基于我自己的代码中Parallel.ForEach的其他用法,故障堆栈跟踪以及下面的注释,我做了一些小的代码更改。到目前为止一切都很好。
基于您的StackTrace并基于TaskReplicator的源代码。运行这些选项为null或复制器的_pendigReplicas – Peter Csala 8月27日在14:48
以下是原始源代码,在极少数情况下可能会失败:
Parallel.ForEach(
ChunkIndexes(processingList.Count,chunkSize),(interval) => {... code here ... });
修改后的代码。仅添加了ParallelOptions参数:
Parallel.ForEach(
ChunkIndexes(processingList.Count,new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount },(interval) => {... code here ... });
仅当在运行使用.net core 2.1编译的C#代码时,才在Linux上观察到原始问题。