C# 使用分区器的ForEachAsync上的ArgumentOutOfRangeException

C# 使用分区器的ForEachAsync上的ArgumentOutOfRangeException,c#,multithreading,asynchronous,foreach,C#,Multithreading,Asynchronous,Foreach,要设置上下文,应用程序在服务器上运行,其中+-20个其他应用程序正在执行一些多线程处理,但此过程仅适用于服务器上的2个应用程序。我在其他应用程序上从未遇到过这种错误,而且都使用了ForEachAsync方法。在这个特定的应用程序上,我不得不添加一些多线程,当我使用ForEachAsync时,有时会出现以下错误: System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

要设置上下文,应用程序在服务器上运行,其中+-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);
        }));
}
publicstatictaskforeachasync(此IEnumerable源代码,Func任务选择器,int-maxParallelism)
{
返回任务.WhenAll(
从Partitioner.Create(source).GetPartitions(maxParallelism)中的分区
选择Task.Run(异步委托{
使用(分区)
while(partition.MoveNext())
等待任务选择器(partition.Current);
}));
}
下面是我如何使用它:

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

await list.ForEachAsync(async a => await Process(param1, param2),parallel);
int parallel=list.Count()<8?list.Count():8;
ForEachAsync(异步a=>Wait进程(param1,param2),并行);
我习惯了很多并行吗?编辑:看起来问题出在空列表上

下面是一个简单的工作示例:

这是我的助手

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);
                }));
        }        
    }
}
使用系统;
使用System.Collections.Concurrent;
使用System.Collections.Generic;
使用System.Linq;
使用系统线程;
使用System.Threading.Tasks;
名称空间公用
{
公共静态类AsyncHelper
{
公共静态任务ForEachAsync(此IEnumerable源、Func taskSelector、int-maxParallelism)
{
返回任务.WhenAll(
从Partitioner.Create(source).GetPartitions(maxParallelism)中的分区
选择Task.Run(异步委托{
使用(分区)
while(partition.MoveNext())
等待任务选择器(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);
var temp=new ConcurrentBag();
int平行=1;
if(someList.Any(c=>c.Valid))
parallel=someList.Count(c=>c.Valid)<8?Count(c=>c.Valid):8;
wait someList.ForEachAsync(异步a=>temp.Add(wait进程(a.Condition、a.State、a.Name)),并行);

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

int parallel = list.Count() < 8 ? list.Count() : 8;
int parallel=list.Count()<8?list.Count():8;
如果target
list
为空,则可以为零,并且零是
Partitioner.Create(…).GetPartitions()调用的无效值


所以,只需检查列表是否为空,如果为空,则不执行任何操作(没有理由对其调用
ForEachAsync

尝试将“.ToArray()”放在.GetPartitions(maxParallelism)之后会发生什么?还有一个问题是getPartitions方法内部的问题——因此我们需要它的代码来调查为什么要这样做而不是使用
Parallel.ForEach
?它已经根据数据大小和核心计数对数据进行了分区,并允许您设置DOP。如果不想阻止等待,请在
任务中运行它。run()
。这不会浪费线程-并行。对于使用当前线程以及来自该cas线程池的线程,我真的很想手动设置并行性,这就是为什么我使用这个method@Gun然后只需在
Parallel.ForEach
@Gun中设置ParallelismOptions.MaxDegreeOfParallelism参数,你到底想做什么?听起来您希望一次处理一批任务,而不是并行处理。这更适合ActionBlock。您可以将DOP设置为ActionBlock,然后开始向其发送消息。它将只处理DOP指定数量的并行消息。您还可以对其输入缓冲区设置限制,以避免未处理的消息淹没它