有一个程序的 mpi 版本,它使用 COMMON 块来存储通过代码到处使用的数组。不幸的是,没有办法以 COMMON 块大小声明数组,只有运行时才知道该数组的大小。因此,作为一种解决方法,我决定将这些数组移到接受 ALLOCATABLE 数组的模块中。也就是说,COMMON 块中的所有数组都消失了,而是使用了 ALLOCATE。所以,这是我在程序中唯一改变的地方。不幸的是,该程序的性能很糟糕(与 COMMON 块的实现相比)。对于 mpi-settings,每个计算节点上都有一个 mpi-process,每个 mpi-process 都有一个线程。我发现了类似的这里提出的问题但不认为(不明白:))如何将其应用于我的案例(每个进程都有一个线程)。我很感激任何帮助。
这是一个简单的例子,它说明了我在说什么(下面是一个伪代码):
“源文件”:
SUBROUTINE ZEROSET()
INCLUDE 'FILE_1.INC'
INCLUDE 'FILE_2.INC'
INCLUDE 'FILE_3.INC'
....
INCLUDE 'FILE_N.INC'
ARRAY_1 = 0.0
ARRAY_2 = 0.0
ARRAY_3 = 0.0
ARRAY_4 = 0.0
...
ARRAY_N = 0.0
END SUBROUTINE
如您所见, ZEROSET() 没有并行或 MPI 的东西。FILE_1.INC, FILE_2, ... , FILE_N.INC 是在 COMMON 块中定义 ARRAY_1, ARRAY_2 ... ARRAY_N 的文件。类似的东西
REAL ARRAY_1
COMMON /ARRAY_1/ ARRAY_1(NX, NY, NZ)
其中 NX、NY、NZ 是在 PARAMETER 指令的帮助下定义明确的参数。当我使用模块时,我只是销毁了所有 COMMON 块,所以 FILE_I.INC 看起来像
REAL, ALLOCATABLE:: ARRAY_I(:,:,:)
然后将上面的“INCLUDE 'FILE_I.INC'”语句更改为“USE FILE_I”。实际上,当执行并行程序时,一个特定的进程不需要整个(NX,NY,NZ)域,所以我计算参数然后分配 ARRAY_I(仅 ONCE!)。
子程序 ZEROSET() 使用 COMMON 块执行 0.18 秒,使用模块执行 0.36 秒(当数组的维度在运行时计算时)。因此,性能恶化了两倍。
我希望现在一切都清楚了。我非常感谢你的帮助。