问题 高度并行的F#程序显示CPU利用率较低


纯函数式编程的一个承诺是它很好地并行化。我正在使用具有平庸结果的F#应用程序来测试此声明。我的程序通过Array.Parallel并行运行大量的MiniMax搜索。 MiniMax算法是纯函数代码 - 没有共享状态,没有锁定,但高度递归,在搜索树时会创建和销毁大量值。根本没有I / O - 一切都在内存中。每个MiniMax搜索需要5-60秒,我在一个带有8个CPU内核的快速盒子上并行运行大约100个。可悲的是,CPU利用率达到65%左右,通常在45-60%的范围内。

我使用Visual Studio Concurrency Visualizer分析了我的应用程序,发现它在大约40%的时间内被阻止。所有阻塞调用似乎都在.NET垃圾收集器或其他.NET内存管理例程中。有没有办法优化这种行为,而无需用C ++等低级语言重写整个程序?很明显,问题是我正在创建和销毁太多的对象,但这在惯用的F#代码中很难避免。也许我错过了同步问题的其他原因?

谢谢。

更新:我做了两个更改:禁用超线程并在我的配置文件中使用gcServer。这使我的测试用例的执行时间从32秒减少到13秒! CPU利用率也高得多。感谢所有提出建议的人。


1284
2017-08-26 17:13


起源

如果你创建了很多实例,并行性可能会受到垃圾收集的限制。无论如何,您需要分析应用程序以确定如何花费时间。如果没有数据,任何人都会猜到为什么你会看到这种行为。 - Brian Rasmussen
我已经分析了应用程序,并且正如我所料,它将大部分时间花在创建子节点的MiniMax算法上。我很乐意分享数据,但我不确定如何在不发布整个应用程序的情况下这样做。 - brianberns
在花费太多时间之前,请确保问题不是那么简单。您是否在启用了超线程的计算机上运行?如果是这样,操作系统可能会报告两倍于您拥有物理内核的逻辑CPU,这可能会使您的CPU使用率报告出现偏差(“虚拟”CPU往往具有相对较低的利用率)。 - Mike Strobel
100 on 8 cpu似乎很多。试试20。 - paparazzo
@MikeStrobel:谢谢,它看起来像是启用了超线程。我会把它关掉,看看它会如何影响结果。 - brianberns


答案:


您应该将应用程序配置为使用服务器垃圾回收。请参阅的文档 gcServer 元素的细节。默认的工作站垃圾收集器不允许分配繁重的程序扩展到多个核心。


9
2017-08-26 18:02