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 获取多个线程?
如果要调用外部 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 中的线程数。
我认为,任何并行化问题都需要仔细考虑,并仔细构建和测试。这其中有很多微妙之处。