4

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

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

我有一台四核机器正在运行,上面的查询在 15 毫秒内运行。但奇怪的是,当我对相同的查询进行 PLINQ 处理时,它花费了更多时间。下面的查询花了大约 40 毫秒。

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>();

这里出了什么问题?

4

2 回答 2

2

当这类问题出现时,答案总是相同的:PLINQ 开销高于收益。

发生这种情况是因为工作项非常小(按字符分组,或从琐碎的输入创建新对象)。当它们更大时效果会更好。

于 2012-09-17T20:49:28.943 回答
0

严格根据您提供的代码很难判断那里发生了什么。

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

另一种可能是,如果您的迭代次数多于可用CPU 的数量,则会导致大量上下文切换。上下文切换很昂贵,并且会影响 CPU 的负载以及操作系统在线程之间切换的速度。

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

于 2012-09-17T18:59:46.557 回答