使用分区程序的ForEachAsync上的ArgumentOutOfRangeException

时间:2018-03-23 09:37:58

标签: c# multithreading asynchronous foreach

要设置上下文,应用程序正在服务器上运行,其中+ -20个其他应用程序正在进行多线程处理,但此过程仅适用于服务器上的2个应用程序。我从来没有在其他应用程序上出现过这种错误,它们都使用ForEachAsync方法。在这个特定的应用程序,我不得不添加一些多线程,我有时会在使用ForEachAsync时出现此错误:

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: partitionCount
   at System.Collections.Concurrent.Partitioner.DynamicPartitionerForIEnumerable`1.GetOrderablePartitions(Int32 partitionCount)
   at System.Collections.Concurrent.OrderablePartitioner`1.GetPartitions(Int32 partitionCount)
   at Common.AsyncHelper.ForEachAsync[T](IEnumerable`1 source, Func`2 taskSelector, Int32 maxParallelism) in ...\AsyncHelper.cs:line 15

以下是方法:

public static Task ForEachAsync<T>(this IEnumerable<T> source, Func<T, Task> taskSelector, int maxParallelism)
{
    return Task.WhenAll(
        from partition in Partitioner.Create(source).GetPartitions(maxParallelism)
        select Task.Run(async delegate {
            using (partition)
                while (partition.MoveNext())
                    await taskSelector(partition.Current);
        }));
}

以下是我如何使用它:

int parallel = list.Count() < 8 ? list.Count() : 8;

await list.ForEachAsync(async a => await Process(param1, param2),parallel);

我是否使用了很多并行性?编辑:看起来空列表就是问题。

这是一个最小的工作示例:

这是我的AsyncHelper

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Common
{
    public static class AsyncHelper
    {
        public static Task ForEachAsync<T>(this IEnumerable<T> source, Func<T, Task> taskSelector, int maxParallelism)
        {
            return Task.WhenAll(
                from partition in Partitioner.Create(source).GetPartitions(maxParallelism)
                select Task.Run(async delegate {
                    using (partition)
                        while (partition.MoveNext())
                            await taskSelector(partition.Current);
                }));
        }        
    }
}

我想要做的是处理一个列表并将结果设置在另一个列表中,其中包含max // = 8:

var temp = new ConcurrentBag<TempResponse>();
int parallel = 1;
if(someList.Any(c => c.Valid))
    parallel = someList.Count(c => c.Valid) < 8 ? someList.Count(c => c.Valid)  : 8;

await someList.ForEachAsync(async a => temp.Add(await Process(a.Condition, a.State, a.Name)),parallel);

1 个答案:

答案 0 :(得分:2)

此错误仅表示您将0作为maxParallelism传递给您的函数。

int parallel = list.Count() < 8 ? list.Count() : 8;

如果目标list为空,则为零;如果Partitioner.Create(...).GetPartitions()调用为零则为零。

因此,只需检查列表是否为空,如果是 - 不执行任何操作(没有理由在其上调用ForEachAsync)。