为什么Parallel.ForEach不运行多个线程?
今天我尝试对foreach
语句进行一些优化,这适用于XDocument
。
优化前:
foreach (XElement elem in xDoc.Descendants("APSEvent").ToList()) { //some operations }
优化后:
Parallel.ForEach(xDoc.Descendants("APSEvent").ToList(), elem => { //same operations });
我在Parallel.ForEach(...)
看到.NET只打开了一个线程! 因此, Parallel
的时间跨度大于标准foreach
。
为什么你认为.NET只开了1个线程? 因为锁定文件? 谢谢
通过设计,Parallel.ForEach可以使用比请求更少的线程来实现更好的性能。 根据MSDN [link] :
默认情况下,Parallel.ForEach和Parallel.For方法可以使用可变数量的任务。 这就是为什么,例如,ParallelOptions类具有MaxDegreeOfParallelism属性而不是“MinDegreeOfParallelism”属性。 这个想法是系统可以使用比请求处理循环更少的线程。
.NET线程池通过允许并行任务的工作线程数随时间变化而动态适应不断变化的工作负载。 在运行时,系统观察增加线程数是否会改善或降低总体吞吐量并相应地调整工作线程数。
像这样用它:
int ParallelThreads = 10; Parallel.ForEach(xDoc.Descendants("APSEvent").ToList(), new ParallelOptions() { MaxDegreeOfParallelism = ParallelThreads }, (myXDOC, i, j) => { //do whatever you want here });
从问题描述中,没有任何东西可以解释为什么TPL不会产生更multithreading。
问题中没有任何证据表明问题。 这可以很容易地修复:你可以在进入循环之前记录线程id,并在循环中做第一件事 。
如果它始终是相同的数字,则TPL无法生成线程。 然后,您应该尝试不同版本的代码,以及哪些更改会触发TPL序列化所有内容。 一个原因可能是您的列表中有少量元素。 TPL对您的集合进行分区,如果您只有几个项目,则最终可能只有一个批次。 这种行为可以通过这种方式进行配置。
可能是你无意中在循环中锁定了,然后你会看到许多不同的数字,但没有加速。 然后,简化代码直到问题消失。
并不总是并行方式比“旧时尚方式”更快http://social.msdn.microsoft.com/Forums/en-US/parallelextensions/thread/c860cf3f-f7a6-46b5-8a07-ca2f413258dd
是的, Document.Load(...)
锁定文件 ,由于线程之间的资源争用,TPL无法使用multithreading的强大function。 尝试将XML加载到Stream
,然后使用Parallel.For(...)
。
你碰巧有一个处理器吗? 在这种情况下,TPL可以将线程数限制为1。 如果集合非常小,可能会发生同样的事情。 尝试更大的collections。 有关如何确定并行度的更多详细信息,请参阅此答案 。