返回介绍

9.4 MPI 和并发 HDF5

发布于 2024-01-25 22:02:55 字数 4438 浏览 0 评论 0 收藏 0

图9-3显示了一个应用程序如何使用并发HDF5。和上述的多线程以及多进程方法相比,基于MPI的应用程序只需要启动多个并发的Python解释器进程。这些解释器进程通过MPI库互相通信。它跟多进程方法的关键区别在于并发HDF5的进程都是同辈,而不像之前我们在使用Pool对象时都是子进程。

图9-3 基于MPI的并发HDF5

当然,这也意味着所有的文件访问都必须通过MPI库来进行协调。否则多个进程会在磁盘的同一文件上“打架”。

幸运的是,HDF5自身已经处理了几乎所有这方面的细节。你需要做的就是用一个特别的驱动打开需要共享的文件,并遵循一些数据一致性方面的约束。

在深入并发HDF5之前,先让我们看一下基于MPI的程序如何跟Python打交道。

9.4.1 一个非常快速的MPI介绍

基于MPI的程序和那些基于多线程或多进程的程序有细微差别。在Python这边不需要显式创建进程,你只要写一个Python脚本并通过一个特殊的程序mpiexec启动。这里是一个MPI的“Hello World”示例:

我们从mpiexec启动这个Python脚本并在4个进程上运行:

上例的COMM_WORLD对象是一个MPI通信器。通过这些对象,进程间通信全都在MPI库内部进行。除了“send”和“receive”方法之外,MPI通信器还支持多种高级的“散布”操作将工作分派给多个进程。本书范围不涉及完整的MPI功能介绍,我们将只介绍于一些基本功能。

COMM_WORLD对象的属性rank是一个标识当前运行的进程整型。你会注意到输出语句打印的rank是“无序”的。和多线程的情形一样,我们的4个进程并发运行,无法确保哪个会先完成。我们会在后面讲述一些基本的进程间同步的方法。

提示


 mpi4py的网站是http://mpi4py.scipy.org,上面详细介绍了如何在Python下使用MPI,还包括大量的例子。

9.4.2 基于MPI的HDF5程序

编译一个MPI模式的h5py很容易。难点在于获取一个编译于“并发”模式的HDF5版本。不过越来越多的Linux发行版已经将它作为一个内建软件包发布。所以,当你在编译h5py时,只需要打开--mpi选项:

提示


 如果你在安装方面遇到了问题,http://www.h5py.org上的指南会为你提供各种建议和示例。本书的示例使用的是OpenMPI编译的HDF5,在Linux下运行。

Python这边,你所需要做的就是在打开文件时指定使用mpio驱动,同时还要指定一个MPI通信器,如COMM_WORLD:

相比于其他的文件驱动,通过mpio打开的文件可以安全地被多进程访问。

下面是我们MPI版本的距离计算代码。注意这里的工作是通过进程的rank隐式分派,而不是像之前的多进程例子那样通过map()显式分派。

9.4.3 集体操作和独立操作

MPI有两种操作风格:集体操作,意味着所有的进程都以同样的顺序执行操作;独立操作,意味着每个进程可以选择自身是否参与操作,时间不限,顺序不限。

HDF5这边主要的约束是:对文件元数据的修改必须通过集体操作完成。下面是一些适用的情形:

打开或关闭一个文件;

创建或删除数据集,组,属性或命名类型;

改变一个数据集的形状;

移动或复制文件中的对象。

一般来说这不算什么大问题。对于你的代码来说,这意味着:当你根据进程的rank(或其他进程间通信的结果)执行不同的代码路径时,确保你只处理数据I/O。对于独立操作的进程来说,只要不涉及元数据操作,读写数据是没有问题的。

下面是一些简单的例子:

如果你违反了这个约束,一般来说你不会得到一个异常,而是会在背后发生各种糟糕的事情,结果有可能会威胁到你的数据。

注意“集体”操作意味着操作是“同步”的。比如,上例所有的进程都以集体操作的方式调用create_dataset,这些进程在调用完成之后都不会停下来等待其他进程跟上。唯一的约束是每个进程都必须以同样的顺序执行调用。

9.4.4 原子操作模式

有时候有必要在多个进程之间同步状态。比如,你可能想要确保分布式计算的第一阶段完成以后才开始下一个部分。MPI提供了多种进程同步机制。最简单的一种叫“同步屏障”。在Python这边,只需要简单调用一个名为Barrier的函数来阻塞自身,直到所有的进程都执行到了程序的同一个地方。

这里有一个例子。该程序会乱序打印“A”和“B”语句:

运行的结果是:

我们的COMM_WORLD通信器包含了Barrier函数。如果我们让所有进程在打印“B”语句之前增加一个屏障,那么结果将是:

了解了Barrier之后,你觉得下面这个双进程程序的输出会是什么?

如果你的答案是“42”那就错了。你可能得到42也可能得到0。这是MPI在一致性方面最令人不爽的一点。默认的写入语义不确保写入操作在Barrier返回之前能完成。为什么?性能。因为MPI一般被用于那些需要上千个处理器来解决的巨型问题,人们通常更愿意牺牲一些一致性来做到尽最大可能得快。

HDF5从1.8.9版本开始,提供了一个功能来解决这个问题。你可以为你的文件打开MPI的“原子操作”模式。这会打开一个底层功能,以牺牲性能为代价换来严格的一致性保证。这意味着Barrier(以及其他MPI同步方法)以你期望的方式跟写入操作互动。下面这个修改后的程序将始终打印“42”:

结果当然就是性能会变差。通常来说,最好的解决方案是不要在进程间通过文件来传递数据。MPI有很棒的进程间通信工具。用它们!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文