PLINQ不能提高性能

4

我写了一个LINQ查询,用于从文本文件中查找唯一字符的频率。我还使用select的帮助将初始结果转换为对象。最终结果以List的形式呈现。 以下是我使用的查询。

charNodes = inputString.GroupBy(ch => ch)
            .Select((ch) => new TNode(ch.Key.ToString(),ch.Count()))
            .ToList<TNode>();

我有一台四核机器正在运行,上述查询用时15ms,但当我使用PLINQ进行同样的查询时,却需要更长的时间。以下查询大约需要40ms。

charNodes = inputString.GroupBy(ch => ch).AsParallel
            .Select((ch) => new TNode(ch.Key.ToString(),ch.Count()))
            .ToList<TNode>();

接下来的查询最糟糕,大约需要83毫秒

charNodes = inputString.AsParallel().GroupBy(ch => ch)
                               .Select((ch) => new TNode(ch.Key.ToString(), ch.Count()))
                               .ToList<TNode>();

这里出了什么问题?

2
输入字符串的长度是多少,你是如何测量时间的? - empi
我使用了计时器类来测量。大小为500KB。 - Prabhu Murthy
@TimSchmelter 他似乎正在使用String作为源,我不确定这与“IO”有什么关系... - Peter Ritchie
@Peter:我认为他想要并行读取文件。但他可能想要阅读:了解 PLINQ 中的加速 - Tim Schmelter
@TimSchmelter他只展示了使用string的PLINQ;我不知道他在处理文件方面是否也是使用PLINQ。但是,如果是的话,那是一个很好的观点。 - Peter Ritchie
@TimSchmelter:不是的。我只是在从文件中提取文本信息后使用了LINQ。 - Prabhu Murthy
2个回答

2
当涉及到这种类型的问题时,答案总是相同的:PLINQ的开销比收益高。
这是因为工作项非常小(按char分组或从微不足道的输入创建新对象)。当它们变大时,效果会更好。

0

基于您提供的代码,真的很难说出那里到底发生了什么。

TPL 使用线程池线程。线程池启动时会大约有 10 个运行线程。 如果您需要更多线程,那么只要有需要,线程池每秒就会创建一个新线程。如果您的循环导致了超过 10 个并行操作,则需要花费时间启动新线程。纠正:并行循环所需的线程数会占用线程池中可用的线程数。线程池尝试保持该池中最少数量的可用线程数,如果它注意到线程正在花费太长时间,则会启动新的线程以进行补偿--这需要资源。框架的许多部分都使用线程池,因此可能会有各种机会来应对线程池的压力。启动线程相当昂贵。

另一个可能性是,如果您的迭代次数大于可用CPU 的数量,那么会产生大量上下文切换。上下文切换是昂贵的,并且会影响 CPU 负载以及操作系统在线程之间切换速度。

如果您提供更多详细信息,例如输入数据,我可以在答案中提供更多详细信息。


2
但是 PLINQ(不像 TPL 的其他部分)使用固定数量的线程,因此它不会使用超过核心数量的线程。 - svick
@svick 是的,你说得对。我在考虑任务...但是,并行循环使用的线程确实会影响线程池。我在我的答案中提供了详细信息。 - Peter Ritchie

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