C - MPI_Barrier似乎不起作用,重新排序 printf (stdout) 消息



以下是一个非常基本的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 %dn", rank);
    MPI_Barrier(MPI_COMM_WORLD);
    printf("Goodbye from %dn", rank);
    MPI_Barrier(MPI_COMM_WORLD);
    printf("Hello 2 from %dn", rank);
    MPI_Barrier(MPI_COMM_WORLD);
    printf("Goodbye 2 from %dn", 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的功能。

Hellos和Goodbyes应该分组

他们不应该,printf功能内部还有其他(MP-Asynchronous)缓冲,而另一种缓冲是stdout从多个MPI进程聚集到单个用户终端。

printf只需打印到LIBC(GLIBC)的内存缓冲区,有时会冲洗到真实的文件描述符(stdout;使用fflush来冲洗缓冲区);fprintf(stderr,...)通常比stdout

具有较小的缓冲

远程任务由Mpirun/Mpiexec启动,通常使用ssh远程外壳,该远程外壳可进行stdout/stderr转发。ssh(也是TCP)将缓冲数据,并且当Mpirun/Mpiexec或其他实体在您的终端显示来自ssh的数据时,可以重新排序(几个数据流已多样地)。

> >

您得到的是第一个过程中的4个字符串被缓冲并在其出口时冲洗(所有字符串均被打印到stdout,通常带有几千键的缓冲液);第二个过程中的另外4个字符串也被缓冲到退出。所有4个字符串均由ssh或其他启动方法发送给您的控制台,作为单个"数据包",并且您的控制台仅以某种顺序显示两条4行的两个数据包," 4_lines_packet_from_id_0; 4_lines_packet_from_id_1;';"或为" 4_lines_packet_from_id_1; 4_lines_packet_from_id_0;"。

MPI_BARRIER应该做?

MPI_Barrier同步代码的一部分,但不能禁用LIBC/GLIBC打印和文件I/O函数中的任何缓冲,也不能禁用ssh或其他远程Shell中的任何缓冲。

如果您的所有流程都在具有同步系统时钟的机器上运行(它们将是您拥有单个机器的时候,并且应该在群集上有ntpd时,您可以将时间戳字段添加到每个printf,以检查该真实订单正在尊重您的障碍(gettimeofday的当前时间外观,没有额外的缓冲)。即使printfssh将重新排序消息,您也可以对时间戳输出进行排序。

#include <mpi.h>
#include <sys/time.h>
#include <stdio.h>
void print_timestamped_message(int mpi_rank, char *s);
{
    struct timeval now;
    gettimeofday(&now, NULL);
    printf("[%u.%06u](%d): %sn", now.tv_sec, now.tv_usec, mpi_rank, s);
}
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);
    print_timestamped_message(rank, "First Hello");
    MPI_Barrier(MPI_COMM_WORLD);
    print_timestamped_message(rank, "First Goodbye");
    MPI_Barrier(MPI_COMM_WORLD);
    print_timestamped_message(rank, "Second Hello");
    MPI_Barrier(MPI_COMM_WORLD);
    print_timestamped_message(rank, "Second Goodbye");
    MPI_Finalize();
    return 0;
}

最新更新