以下是一个非常基本的MPI程序
#include <mpi.h>
#include <stdio.h>
int main(int argc, char * argv[]) {
int rank;
int size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Barrier(MPI_COMM_WORLD);
printf("Hello from %d\n", rank);
MPI_Barrier(MPI_COMM_WORLD);
printf("Goodbye from %d\n", rank);
MPI_Barrier(MPI_COMM_WORLD);
printf("Hello 2 from %d\n", rank);
MPI_Barrier(MPI_COMM_WORLD);
printf("Goodbye 2 from %d\n", rank);
MPI_Finalize();
return 0;
}
您希望输出为(对于2个进程)
Hello from 0
Hello from 1
Goodbye from 1
Goodbye from 0
Hello 2 from 1
Hello 2 from 0
Goodbye 2 from 0
Goodbye 2 from 1
或者类似的东西(应该对hellos和goodbyes进行分组,但不保证流程顺序)。
这是我的实际输出:
Hello from 0
Goodbye from 0
Hello 2 from 0
Goodbye 2 from 0
Hello from 1
Goodbye from 1
Hello 2 from 1
Goodbye 2 from 1
我是否从根本上误解了MPI_Barrier应该做什么?从我所知,如果我只使用它一次,那么它给了我预期的结果,但不仅如此,它似乎绝对没有。
我之前已经发现许多类似的问题,但我所看到的问题中的问题误解了MPI_Barrier的功能。
答案 0 :(得分:0)
应该将hellos和再见分组
他们不应该在printf
函数内部有额外的(MPI异步)缓冲,而另一个缓冲是stdout
从多个MPI进程收集到单个用户终端。
printf
只打印到libc(glibc)的内存缓冲区,有时刷新到真实文件描述符(stdout
;使用fflush
刷新缓冲区);和fprintf(stderr,...)
通常比stdout
远程任务由mpirun / mpiexec启动,通常使用ssh
远程shell,执行stdout
/ stderr
转发。 ssh
(以及TCP也将)缓冲数据,当来自ssh
的数据通过mpirun / mpiexec或其他实体(多个数据流被多路复用为一个)时,可以重新排序。
你得到的是从第一个进程中的4个字符串缓冲并在其出口处刷新(所有字符串都打印到stdout
,通常具有几千字节的缓冲区);并且第二个进程中的另外4个字符串也被缓冲,直到退出。所有4个字符串都由ssh
或其他启动方法发送到您的控制台,作为单个&#34;数据包&#34;并且你的控制台只显示两个包含4行的包,每个包含一些顺序,&#34; 4_lines_packet_from_id_0; 4_lines_packet_from_id_1;&#34;或作为&#34; 4_lines_packet_from_id_1; 4_lines_packet_from_id_0;&#34;。
MPI_Barrier应该做什么?
MPI_Barrier
同步部分代码,但它不能在libc / glibc打印和文件I / O函数中禁用任何缓冲,也不能在ssh
或其他远程shell中禁用。
如果所有进程都在具有同步系统时钟的计算机上运行(它们将在您拥有单个计算机时运行,并且它们应该在您的群集上有ntpd
时),则可以为每个{{{}添加时间戳字段1}}检查真正的顺序是否尊重你的障碍(printf
查找当前时间,并且没有额外的缓冲)。即使gettimeofday
和printf
重新排序邮件,您也可以对带时间戳的输出进行排序。
ssh