C#-并行Foreach缓慢创建线程

C#-并行Foreach缓慢创建线程,c#,multithreading,parallel-processing,task-parallel-library,C#,Multithreading,Parallel Processing,Task Parallel Library,我有一个IEnumerable,其中有很多项需要并行处理。这些项目不是CPU密集型的。 理想情况下,这些项目应在100个或更多线程上同时执行 我已经尝试使用Parallel.ForEach()来实现这一点。这是可行的,但问题是新线程的生成速度太慢。Parallel.Foreach()需要(太)长的时间才能到达100个线程。我知道存在MaxDegreeOfParallelism属性,但这是最大值,而不是最小值 有没有办法在100个线程上立即执行foreach? 我们希望避免使用ThreadPool

我有一个IEnumerable,其中有很多项需要并行处理。这些项目不是CPU密集型的。 理想情况下,这些项目应在100个或更多线程上同时执行

我已经尝试使用Parallel.ForEach()来实现这一点。这是可行的,但问题是新线程的生成速度太慢。Parallel.Foreach()需要(太)长的时间才能到达100个线程。我知道存在MaxDegreeOfParallelism属性,但这是最大值,而不是最小值

有没有办法在100个线程上立即执行foreach? 我们希望避免使用ThreadPool.SetMinThreads,因为它会影响整个流程


使用自定义分区器是否有可行的解决方案?

我成功地使用了ThreadPool而不是Parallel:

public static void ThreadForEach<T>(this IEnumerable<T> items, Action<T> action)
{
    var mres = new List<ManualResetEvent>();

    foreach (var item in items)
    {
        var mre = new ManualResetEvent(false);

        ThreadPool.QueueUserWorkItem((i) =>
        {
            action((T)i);
            mre.Set();
        }, item);

        mres.Add(mre);
    }

    mres.ForEach(mre => mre.WaitOne());
}
publicstaticvoidthreadforeach(此IEnumerableems,Action)
{
var mres=新列表();
foreach(项目中的var项目)
{
var mre=新手动重置事件(错误);
ThreadPool.QueueUserWorkItem((i)=>
{
作用((T)i);
mre.Set();
},项目);
添加(mre);
}
mres.ForEach(mre=>mre.WaitOne());
}
在我不得不使用这个的情况下,它比使用Parallel.ForEach的尝试运行得更快。我只能推测,这是因为它试图使用已经存在的线程(而不是承担创建新线程的开销)

我正在ping很多设备,超时时间为5秒。如果只使用4个线程(4个核心),您将如何尽可能快地完成这项工作

我将假设您的ping设备位于局域网上,并且每个设备都可以通过IP地址识别和访问

namespace PingManyDevices {

    public class DeviceChecker {                

        public async Task<PingReply[]> CheckAllDevices(IEnumerable<IPAddress> devices) {
            var pings = devices.Select(address => new Ping().SendPingAsync(address, 5000));
            return await Task.WhenAll(pings);
        }
        /***
        * Maybe push it a little further
        ***/ 
        public async Task<PingReply[]> CheckAllDevices(IEnumerable<IPAddress> devices) {
            var pings = devices.AsParallel().Select(address => new Ping().SendPingAsync(address, 5000));
            return await Task.WhenAll(pings);
        }          
    }
} 
名称空间PingManyDevices{
公共类设备检查器{
公共异步任务CheckAllDevices(IEnumerable设备){
var pings=devices.Select(address=>new Ping().SendPingAsync(address,5000));
返回等待任务时(pings);
}
/***
*也许再往前推一点
***/ 
公共异步任务CheckAllDevices(IEnumerable设备){
var pings=devices.AsParallel().Select(地址=>new Ping().SendPingAsync(地址,5000));
返回等待任务时(pings);
}          
}
} 

Well
Parallel.ForEach
使用线程池,因此它是规则,因此
SetMinThreads
似乎是唯一的选项(如果您想特别使用
Parallel.ForEach
),您能否提供一个示例来演示您的处理过程。它是IO绑定的还是CPU绑定的,它是多步骤进程。。等等?但是,如果您的任务不是CPU密集型的(因此-大部分是IO密集型的)-您可以使用async\Wait结合SemaphoreSlim来限制并发性,例如这里(但不要像那里那样使用Task.Run(Wait…)。如果您的操作不是CPU密集型的,那么您首先不应该创建额外的线程。创建一堆线程却让它们无所事事(因为你显然没有工作让它们做)会让你的代码变慢,消耗更多资源,而不是更快。在4个内核上同时运行100个线程需要更长的时间,而不是一次使用4个线程,因为在线程之间切换涉及到成本。不过我建议你自己试试,也许你有100多个内核。你可以完全避免讨论线程,也可以完全避免foreach,使用一个简单的PLINQ查询。但是,如果OP的处理以任何方式受到IO限制,则需要转向同步解决方案。Parallel也使用线程池。平行线没有断开。无论如何,你的代码有很多问题。首先,它使用
列表
而不是并发集合。其次,这完全是多余的<代码>等待任务.WaitAll(items.Select(it=>Task.Run(action(it)).ToArray())会做完全相同的事情最后,
并行
意味着数据并行。这意味着你想要处理大量的数据,而不是大量的任务。通常你需要的任务不超过处理每个数据分区的核心数。如果操作阻塞,那就是滥用了
并行