具有 IEnumerables 的多线程,并行评估几次,评估起来很昂贵,不使用100%CPU 。示例是与Concat()结合使用的Aggregate()函数:
// Initialisation.
// Each IEnumerable<string> is made so that it takes time to evaluate it
// everytime when it is accessed.
IEnumerable<string>[] iEnumerablesArray = ...
// The line of the question (using less than 100% CPU):
Parallel.For(0, 1000000, _ => iEnumerablesArray.Aggregate(Enumerable.Concat).ToList());
问题:为什么对IEnumerables进行多次并行评估的并行代码不使用100%CPU??该代码不使用锁或等待,因此这种行为是意外的。文章的末尾有一个完整的代码来模拟这一点。
注释和修改:
Enumerable.Range(0, 1).Select(__ => GenerateLongString())
完整代码最后的Enumerable.Range(0, 1).Select(__ => GenerateLongString()).ToArray().AsEnumerable()
,
GenerateLongString()
在GC上不那么繁重,而在CPU上更繁琐,则CPU变为100%。因此原因与该方法的实现有关。但是,有趣的是,如果在没有IEnumerable的情况下调用GenerateLongString()
的当前形式,则CPU也会达到100%:
Parallel.For(0, int.MaxValue, _ => GenerateLongString());
GenerateLongString()
的繁重并不是这里的唯一问题。clr.dll!WKS::gc_heap::wait_for_gc_done
,
string.Concat()
的{{1}}内部发生的。完整代码:
GenerateLongString()
答案 0 :(得分:2)
您的线程在clr.dll!WKS::gc_heap::wait_for_gc_done
上被阻塞的事实表明,垃圾收集器是应用程序的瓶颈。您应该尽可能地限制程序中堆分配的数量,以减轻对gc的压力。
也就是说,还有另一种加快处理速度的方法。默认情况下,在台式机上,GC配置为使用计算机上有限的资源(以避免降低其他应用程序的速度)。如果要充分利用可用资源,则可以activate server GC。此模式假定您的应用程序是计算机上运行的最重要的东西。它将显着提高性能,但会使用更多的CPU和内存。