为什么Parallel.ForEach没有运行多个线程?

24

今天我尝试对在XDocument上运行的foreach语句进行一些优化。

优化之前:

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只开启了一个线程?是由于文件锁定吗? 谢谢


10
你的计算机有多少个核心或逻辑处理器?列表中有多少个元素? - Christian.K
1
你可能想通读一下这个 - Christian.K
1
你怎么知道只有一个线程?如果你的代码运行得更慢,并不意味着只有一个线程,可能是你的逻辑中的锁导致了延迟。并行会正确地完成它的工作。 - Akash Kava
1
不是直接相关的内容,但有趣的是人们应该知道何时使用Parallel.ForEach和何时使用PLINQ:http://blog.mssoftwareconsulting.com/msswc/blog/file.axd?file=WhenToUseParallelForEachOrPLINQ.pdf - Tim Schmelter
我想知道如何知道有多少线程正在使用parallel.foreach来完成任务?请指导我。谢谢。 - Thomas
显示剩余7条评论
6个回答

15

并不是错误,Parallel.ForEach可能会使用比请求的线程更少的线程以实现更好的性能。根据MSDN [链接]:

默认情况下,Parallel.ForEach和Parallel.For方法可以使用变量数量的任务。这就是为什么例如ParallelOptions类具有MaxDegreeOfParallelism属性而不是“MinDegreeOfParallelism”属性。 这个想法是系统可以使用比请求的线程更少的线程来处理循环。

.NET线程池通过允许并行任务的工作线程数量随时间动态变化,适应于不断变化的工作负载。在运行时,系统观察是否增加线程数量可以改善整体吞吐量或降低整体吞吐量,并相应地调整工作线程数量。


1
谢谢,但这只是说它“可以”打开较少的线程。除了感觉如此之外,它并没有解释为什么。 - Suncat2000

2

从问题描述中,没有任何说明TPL为什么没有生成更多的线程。

在问题中没有任何证据表明这是问题所在。这很容易解决:您可以在进入循环之前记录线程ID,并将其作为您的循环内的第一件事

如果始终是相同的数字,则是TPL无法生成线程。然后,您应该尝试不同版本的代码以及何种更改触发TPL序列化所有内容。一个原因可能是列表中的元素数量较少。TPL会对您的集合进行分区,如果只有几个项目,您可能最终只会得到一个批次。顺便说一下,这种行为是可配置的。

可能是您在循环中无意中锁定了某个锁,那么您将看到许多不同的数字,但不会加速。然后,简化代码直到问题消失。



0

使用方法如下:

int ParallelThreads = 10;
Parallel.ForEach(xDoc.Descendants("APSEvent").ToList(), new ParallelOptions() { MaxDegreeOfParallelism = ParallelThreads }, (myXDOC, i, j) =>
{
 //do whatever you want here 
});

1
请注意,MaxDegreeOfParallelism 设置的是最大线程数,而不是最小值。因此,当您想要限制或减少使用的线程/核心数量时非常有用。 - coloboxp

-1

是的,没错,Document.Load(...) 锁定了文件,由于线程之间的资源争用,TPL无法充分利用多个线程的优势。尝试将XML加载到一个Stream中,然后使用Parallel.For(...)


8
这只能解释为什么只有一个线程在_进行_,而不能解释为什么只有一个线程被_创建_ - 就像原始贴子所声称的那样。Parallel.ForEach无法(合理地)了解正在迭代的集合(它只"看到"传递进来的List<XElement>,并且假设它没有任何特殊的实现是不合理的)。此外,ToList基本上会急切地获取所有元素,因此在这里锁定(以及从文件中读取)不应该有任何影响。 - Christian.K

-1

你是否只有一个处理器?在这种情况下,TPL 可能会将线程数限制为一个。如果集合非常小,则可能会发生相同的事情。尝试更大的集合。 请参阅此答案以了解如何确定并行度的详细信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接