WithDegreeOfParallelism(N>CPU count)

本文关键字:CPU count gt WithDegreeOfParallelism | 更新日期: 2023-09-27 18:37:12

System.Threading.ThreadPool.SetMaxThreads(50, 50);
File.ReadLines().AsParallel().WithDegreeOfParallelism(100).ForAll((s)->{
/*
some code which is waiting external API call 
and do not utilize CPU 
*/
});

我从未在我的系统中获得超过CPU计数的线程数。是否可以使用 PLINQ 并为每个 CPU 获取多个线程?

WithDegreeOfParallelism(N>CPU count)

如果要调用外部 Web API,则可能会达到并发同时连接数的限制,该限制设置为 2。在应用程序开始时执行以下操作:

System.Net.ServicePointManager.DefaultConnectionLimit = 4096;
System.Net.ServicePointManager.Expect100Continue = false;

试试是否有帮助。如果没有,则尝试并行化的例程中可能存在其他一些瓶颈。

此外,就像其他响应者所说的那样,ThreadPool 根据负载决定启动多少线程。根据我对 TPL 的经验,我看到线程大小随着时间的推移而增加:应用程序运行的时间越长,负载越重,启动的线程就越多。

PLINQ 使用爬山算法来确定 TPL 使用的线程池的最佳大小。我认为,如果您在任务中投入大量 I/O,那么看到比 CPU 计数更多的线程是很可爱的。

也就是说,我从未见过超过 CPU 计数的线程:) .但也许我从来没有遇到过正确的情况。

我使用以下代码对此进行了测试:

var lines = Enumerable.Range(0, 200).ToArray();
int currentThreads = 0;
int maxThreads = 0;
object l = new object();
lines.AsParallel().WithDegreeOfParallelism(100).ForAll(
    s =>
    {
        lock (l)
        {
            currentThreads++;
            if (currentThreads > maxThreads)
            {
                maxThreads = currentThreads;
                Console.WriteLine(maxThreads);
            }
        }
        Thread.Sleep(3000);
        lock (l)
        {
            currentThreads--;
        }
    });
Console.WriteLine();
Console.WriteLine(maxThreads);

基本上,它记录当前并发执行迭代的次数,然后保存遇到的最大值。

结果差异很大,在 15 到 25 之间,但它总是比我的计算机拥有的 CPU 数量多得多 (4)。增加休眠时间会增加最大并发线程数。所以看起来这里的限制因素是ThreadPool:它会慢慢地创建新线程,尤其是当作业相对较快地完成时。

如果要增加使用的线程数,则需要使用 SetMinThreads()(而不是 SetMaxThreads() )。如果我将最小值设置为 50,则实际使用的线程数约为 60。

但是,拥有数十个线程只执行任何操作只是等待是非常低效的,尤其是在内存消耗方面。应考虑改用异步方法。

PLINQ 不适合这种情况。我发现下一篇文章对我有用。http://msdn.microsoft.com/en-us/library/hh228609(v=vs.110).aspx

简短的回答:没有。

线程量仅取决于.Net Framework运行时。没有用于控制 TPL(任务并行库)使用的线程数的开发人员控件。

编辑

感谢其他一些反馈:实际上可以(但不建议)手动控制 PLINQ 和 TPL 使用的 ThreadPool 中的线程数。

我认为,任何并行化问题都需要仔细考虑,并仔细构建和测试。这其中有很多微妙之处。