12

我使用 F# 开发了 Lattice Boltzmann(流体动力学)代码。我现在正在 24 核、128 GB 内存服务器上测试代码。该代码基本上由一个用于时间演化的主要递归函数和一个用于 3D 维空间迭代的 System.Threading.Tasks.Parallel.For 循环组成。3D 空间是 500x500x500 大,一个时间周期需要永远:)。

let rec timeIterate time =
  // Time consuming for loop
  System.Threading.Tasks.Parallel.For(...)

我希望服务器使用所有 24 个内核,即有 100% 的使用率。我观察到的使用率在 1% - 30% 之间。

我的问题是:

  1. F# 是否适合在此类服务器上进行 HPC 计算?
  2. 将 100% 的 CPU 用于实际问题是否现实?
  3. 我应该怎么做才能获得高速?一切都在一个大的并行循环中,所以我希望这就是我应该做的一切......
  4. 如果 F# 不是合适的语言,那是什么语言?

感谢您的任何建议。

编辑:如果有人有兴趣看一下,我愿意分享代码。

EDIT2:这是代码的剥离版本:http: //dl.dropbox.com/u/4571/LBM.zip 它没有做任何合理的事情,我希望我没有通过剥离代码引入任何错误:)

启动文件是 ShearFlow.fs,文件底部是

let rec mainLoop (fA: FArrayO) (mR: MacroResult) time =
  let a = LBM.Lbm.lbm lt pA getViscosity force g (fA, mR)
4

7 回答 7

5

1. F# 是否适合在此类服务器上进行 HPC 计算?

作为一种语言,它 (F#)可以鼓励并行运行良好的代码——至少其中一部分是减少状态可变性和高阶函数——这是一种可以而不是一种意志。然而,HPC 有许多专业的编程语言/编译器和/或负载分配方式(例如共享统一内存或分布式微内核)。F# 只是一种通用的编程语言:它可能有权访问或不能访问各种技术(例如,绑定可能存在也可能不存在)。(这甚至适用于非分布式并行计算。)

2. 将 100% 的 CPU 用于实际问题是否现实?

这取决于限制因素是什么。和我的朋友聊天5k+100k+ 核心 HPC 研发,数据交换空闲时间通常是限制因素(当然,这是一个更高的 n :-),因此即使是 IO 减少(效率或不同算法)的微小改进也可能导致显着收益。不要忘记在同一台机器上的 CPU/缓存之间简单地移动数据的成本!当然,还有越来越慢的磁盘 IO……

3. 我应该怎么做才能获得高速?一切都在一个大的并行循环中,所以我希望这就是我应该做的一切......

找出慢的部分在哪里并修复它(它们) :-) 例如运行配置文件分析。请记住,它可能需要使用完全不同的算法或方法。

4. 如果 F# 不是合适的语言,那是什么语言?

虽然我不反对它,但我的博士朋友使用/在Charm++上工作:它是一种非常专注于分布式并行计算的语言(不是所讨论的环境,但我试图说明一点:-) -- F# 尝试成为一种体面的通用语言。

于 2010-11-04T20:44:13.543 回答
4

F# 应该和任何语言一样好。决定性能的更多是你编写代码的方式,而不是语言本身。

如果您的计算受 CPU 限制,您应该能够接近 100%,至少在 90% 的高范围内。

此处未获得 100% CPU 可能有多种原因。

  1. 您的计算可能受 I/O 限制(您是否在 for 循环中执行文件或网络操作?)
  2. 你有同步问题,比如很多锁定(你在线程之间有共享状态,包括你“提交”结果的位置吗?)
于 2010-11-04T13:08:01.700 回答
3

F# 是否适合在此类服务器上进行 HPC 计算?

我不太了解 F#,但我宁愿怀疑它非常适合。它拥有所有正确的工具,而且它是一种功能性语言,适合高度并行执行。

将 100% 的 CPU 用于实际问题是否现实?

是的,或者非常接近。但事实上,如果您有 24 个内核,您的应用程序应该使用 2400% 的 CPU 功率!至少,这就是它通常的显示方式。如果您观察到 30% 的使用率,很可能它运行在单个内核上,甚至没有使用那个内核。

我应该怎么做才能获得高速?一切都在一个大的并行循环中,所以我希望这就是我应该做的一切......

好吧,你没有显示你的代码。我只能假设您的代码中的某些内容阻止它并行执行。

或者(1% 到 30% 的 CPU 使用率指向这一点)您的问题实际上不是计算限制,并且计算一直在等待其他资源,例如辅助内存。这不一定取决于问题——毕竟,流体动力学一个受计算限制的问题!– 而是在您的特定实施上。到目前为止,很多都指向资源争用。

于 2010-11-04T13:06:35.397 回答
2
  1. 我认为 F# 尚未成为 HPC 的主流,Fortran、C 和 C++ 占主导地位,但我看不出有什么特别的理由应该避免它。

  2. 不,不是,在任何延长的时间段内都不会。迟早所有(有问题的断言)HPC代码都会受到内存带宽的限制——CPU处理数字的速度比RAM加载和存储的速度要快得多。在长时间运行的计算中,您可以使用 CPU 可以执行的理论最大 FLOP 数的 10%。

  3. 我不太了解 F#,无法为您的配置提供具体建议(我是那些 HPC Fortran 程序员之一)。但总的来说,您需要确保良好的负载平衡(即所有内核都做相同数量的工作),高效且有效地使用内存层次结构(随着语言变得“更高级别”,这变得很困难,因为它们往往会使它变得困难在低级别管理流程),你能做的最好的事情就是选择最好的算法。最好的并行算法不一定是最好的并行串行算法,我怀疑最好的功能(实现)算法可能不是最好的(强制实现)算法。

  4. Fortran。

于 2010-11-04T13:09:35.350 回答
1

线程池的最大线程数取决于各种情况。

来自MSDN

最大线程池线程数

可以排队到线程池的操作数仅受可用>内存限制;但是,线程池限制了进程中可以同时处于活动状态的线程数。从 .NET Framework 版本 4 开始,进程的线程池的默认大小取决于几个因素,例如虚拟地址 > 空间的大小。进程可以调用 GetMaxThreads 方法来确定线程数。

您可以使用 GetMaxThreads 和 SetMaxThreads 方法控制最大线程数。

如有必要,还可以尝试增加 MinThreads。您系统上的内核数量可能会导致线程池优化算法失效?值得一试。

同样,来自MSDN

线程池按需提供新的工作线程或 I/O 完成线程,直到达到每个类别的指定最小值。您可以使用 GetMinThreads 方法来获取这些最小值。

当达到最小值时,线程池可以创建额外的线程或等待某些任务完成。从 .NET Framework 4 开始,线程池创建和销毁工作线程以优化吞吐量,吞吐量定义为每单位时间完成的任务数。线程太少可能无法最佳利用可用资源,而线程太多可能会增加资源争用。

于 2010-11-04T13:35:47.840 回答
1

函数式编程侧重于高级抽象,即,您将常见的编程模式抽象出来并使其通常可重用。高性能计算是让事情并行运行,考虑不同线程之间的位,考虑数据局部性以使缓存命中率更高。这是两个不同的方向。

如今,人们倾向于认为 FP 是所有并行的灵丹妙药,包括高性能计算。不。否则你会看到很多 FP 论文发表在高性能会议上。其实很少。

您现在使用的是 Task Parallel 库,它是 C#/F#/VB 的 .Net 库。不是 F# 特定的。我相信它本身是用 C# 编写的。

考虑到这一点,让我们回到你的问题。为什么不能使用 100% CPU?帮助您找到瓶颈的技能与 F# 关系不大。对您的程序进行分析,查看是否有一些线程正在等待其他线程完成(您需要完成 Paralle.For 中的所有计算才能继续)。

于 2010-11-05T01:29:39.510 回答
0

您是否尝试过使用 Visual Studio 中包含的线程分析工具:使用性能向导中的并发分析器选项?

于 2010-11-04T13:12:16.833 回答