在上一篇中我们介绍了 mpi4py 中的不连续读/写和集合 I/O 操作,下面我们将介绍 mpi4py 中读/写文件中数组的方法。
在并行科学计算程序中,经常会涉及到读/写文件中的数组(包括子数组和分布式数组,数组可以是多维的,规则分布或不规则分布的)。MPI 提供了相应的方法使这种类型的操作方便而高效。
在并行应用中,数组一般会按照某种方式分布在多个进程中,而程序需要将这些分布在各个进程中的数组按照整体的行优先顺序(C 数组的排列方式)或列优先顺序(Fortran 数组的排列方式)写入到文件中,或者从文件中将一个整体的数组读取并分布到各个进程上。比如像下图所示,一个两维的 m 行 n 列的数组分布在一个 2 × 3 的进程网格上。
如果要将这些进程中的数据按照行优先的排列方法整体地写入到一个文件中,则可以看出某个进程本地的子数组并不是连续地位于文件中的某块区域,因此我们必须执行一种不连续的数据写过程,我们可以利用上一篇所介绍的相关方法。因为类似这样的数据读/写操作是如此的普遍,而要自己创建描述这种操作的数据类型又是麻烦而且容易出错的,因此 MPI 提供了相应的数据描述方法供我们方便地使用。利用这些数据描述方法并结合集合 I/O 操作,往往可以允许我们通过仅仅一次读/写调用完成对这个分布式数组的读/写操作,并且 MPI 实现可能提供高的优化性能,尽管执行的是非连续的读/写。下面对执行数据描述方法做简要的介绍,用这些数据描述方法创建的数据类型可以作为文件视图的 filetype 以实现对数组的方便而高效的读/写操作。
分布式数组
分布式数组数据描述方法是一种方便易用的描述一个线性化的规则多维数组中一个子数组位置的派生数据类型创建方法,其方法接口如下:
MPI.Datatype.Create_darray(self, int size, int rank, gsizes, distribs, dargs, psizes, int order=ORDER_C)
该方法在前面数据类型创建方法中作过相应的介绍,这里不再赘述,只强调几点:在创建分布式数组派生数据类型时,进程网格总是假定与整体数组有着相同数目的维数,如果整体数组在某个维度上不分布,进程网格也不能省略掉该维度,而必须设置该维度上的进程数为 1。比如说,一个 10 × 10 的整体数组分布在 4 个进程上,则这 4 个进程可以排成 2 × 2 的进程网格,1 × 4 进程网格,或是 4 × 1 进程网格。进程网格必须总是按照行优先的顺序(即 C 数组排列顺序)。如果程序中要使用一种不同的进程网格排列顺序,则不能使用该数据类型创建方法,可以考虑下面介绍的子数组类型创建方法或其它的派生数据类型创建方法。
子数组
子数组数据类型描述方法是另一种描述一个线性化的规则多维数组中一个子数组位置的派生数据类型创建方法,其方法接口如下:
MPI.Datatype.Create_subarray(self, sizes, subsizes, starts, int order=ORDER_C)
该方法在前面数据类型创建方法中作过相应的介绍,这里不再赘述,只强调几点:子数组数据类型创建方法只能描述块状分布的子数组,而不能像上面介绍的分布式数组创建方法那样描述循环分布及更普遍的块状循环分布。另外,子数组数据类型创建方法对进程的拓扑顺序没有要求,可以是列优先的顺序,还可以是其它任何排列顺序。一般为了方便,可以使用虚拟进程拓扑方法首先按照某种虚拟拓扑结构安排好相应的进程。
子数组数据类型描述方法也能很好地用来描述一类带有 ghost area 的分布式数组。在一些应用中,分布于某个进程的本地数组在一些维度上会包含几个额外的行或列,这些额外的区域,并不是该进程的本地数组的实际部分,通常被称做 halo 或者 ghost area。这些 ghost area 一般是用来存储邻近进程的行或列以利于该进程和邻近进程之间的通信及便于对本地数组的相关操作。下图给出了一个带有 ghost area 的本地数组的例子。这个本地数组实际上只有 100 行 100 列,但是在其外围包裹了 4 行或 4 列的 ghost area,使其变成了一个 108 行 108 列的数组。可以看出,在这个带有 ghost area 的本地数组中,处于中心部位的实际数组在内存中的排布也是不连续的。另外,分布在各个进程中的数组作为一个整体如果要写入到文件或从文件读入各个进程,也会涉及不连续的读/写过程。在这种情况下,数据的 I/O 操作在内存和文件中都是不连续的,但是借助子数组数据类型及集合 I/O 读写方法,我们依然可以通过一次读/写调用完成相应的操作。
不规则分布式数组
MPI 也提供了方法来读/写不规则的分布式数组,只要使用合适的 filetype 来设置文件视图即可。如果和集合 I/O 方法结合起来使用,MPI 实现也可能以高的性能完成对这类数据的读/写操作,虽然这类读/写操作一般认为是很难优化的。不规则的分布是指不能很好地用简单的数学表达的分布形式,