【发布时间】:2014-08-26 17:13:45
【问题描述】:
纯函数式编程的一个承诺是它可以很好地并行化。我正在使用结果平庸的 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 利用率也高得多。感谢所有提出建议的人。
【问题讨论】:
-
如果您要创建大量实例,并行性可能会受到垃圾收集的限制。在任何情况下,您都需要对应用程序进行分析以了解时间是如何花费的。如果没有数据,任何人都会猜测您为什么会看到这种行为。
-
我已经对应用程序进行了分析,正如我所料,它大部分时间都花在 MiniMax 算法中创建子节点。我很乐意分享数据,但如果不发布整个应用程序,我不知道该怎么做。
-
在您花太多时间在此之前,请确保问题不简单。您是否在启用了超线程的机器上运行?如果是这样,操作系统报告的逻辑 CPU 数量可能是物理内核的两倍,这可能会导致 CPU 使用情况报告出现偏差(“虚拟”CPU 的使用率往往相对较低)。
-
100 on 8 cpu 似乎很多。试试 20。
-
@MikeStrobel:谢谢,看起来超线程已启用。我会关掉它,看看它对结果有何影响。
标签: .net multithreading memory-management f# parallel-processing