我使用MPI_Barrier的OpenMPI实现有一些同步问题:
int rank;
int nprocs;
int rc = MPI_Init(&argc, &argv);
if(rc != MPI_SUCCESS) {
fprintf(stderr, "Unable to set up MPI");
MPI_Abort(MPI_COMM_WORLD, rc);
}
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
printf("P%d\n", rank);
fflush(stdout);
MPI_Barrier(MPI_COMM_WORLD);
printf("P%d again\n", rank);
MPI_Finalize();
对于mpirun -n 2 ./a.out
输出应该是: P0 P1 ......
输出有时: P0 再次P0 P1 P1再次
发生了什么事?
答案 0 :(得分:13)
打印输出行在终端上显示的顺序不一定是打印内容的顺序。您正在使用共享资源(stdout
),因此始终存在排序问题。 (fflush
在这里没有用,stdout
无论如何都是行缓冲。)
您可以尝试使用时间戳为输出添加前缀,并将所有这些保存到不同的文件中,每个MPI进程一个。
然后,要检查日志,您可以将两个文件合并在一起,并根据时间戳进行排序。
那么你的问题就会消失。
答案 1 :(得分:11)
MPI_Barrier()没有错。
作为Jens mentioned,您没有看到预期输出的原因是因为stdout在每个进程上都被缓冲。无法保证来自多个进程的打印将按顺序显示在调用进程中。 (如果每个进程的stdout被转移到主进程实时打印,那将导致大量不必要的通信!)
如果您想说服自己屏障有效,可以尝试写入文件。将多个进程写入单个文件可能会导致额外的复杂化,因此您可以将每个proc写入一个文件,然后在屏障之后交换他们写入的文件。例如:
Proc-0 Proc-1
| |
f0.write(..) f1.write(...)
| |
x ~~ barrier ~~ x
| |
f1.write(..) f0.write(...)
| |
END END
示例实施:
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char filename[20];
int rank, size;
FILE *fp;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (rank < 2) { /* proc 0 and 1 only */
sprintf(filename, "file_%d.out", rank);
fp = fopen(filename, "w");
fprintf(fp, "P%d: before Barrier\n", rank);
fclose(fp);
}
MPI_Barrier(MPI_COMM_WORLD);
if (rank < 2) { /* proc 0 and 1 only */
sprintf(filename, "file_%d.out", (rank==0)?1:0 );
fp = fopen(filename, "a");
fprintf(fp, "P%d: after Barrier\n", rank);
fclose(fp);
}
MPI_Finalize();
return 0;
}
运行代码后,您应该得到以下结果:
[me@home]$ cat file_0.out
P0: before Barrier
P1: after Barrier
[me@home]$ cat file_1.out
P1: before Barrier
P0: after Barrier
对于所有文件,“后障碍”语句将始终显示在以后。
答案 2 :(得分:3)
MPI程序无法保证输出顺序。
这与MPI_Barrier完全没有关系。
另外,我不会花太多时间来担心MPI程序的输出排序。
实现这一目标的最优雅的方法,如果你真的想要,就是让进程将他们的消息发送到一个等级,比如排名0,让等级0按照它接收或排序的顺序打印输出。行列。
同样,不要花太多时间尝试从MPI程序订购输出。这是不实际的,没什么用处。
答案 3 :(得分:0)
在此处添加以前的答案后,您的MPI_BARRIER可以正常工作。
尽管,如果您只是想使其运行,可以强制暂停执行(SLEEP(1)
)一会儿,以使输出赶上。