【问题标题】:difficulty understanding MPI scatter and gather in C难以理解 C 中的 MPI 分散和聚集
【发布时间】:2019-02-11 02:06:44
【问题描述】:

我正在尝试学习使用 MPI。下面是我测试 MPI 分散和聚集的简单程序。我不明白它是如何工作的以及为什么会产生结果

1 2 3 4 4 5 6 7 8 9 10 11

而不是预期

1 2 3 4 5 6 7 8 9 10 11 12

我能找到的文档和所有示例都太复杂/措辞太差,我无法理解。我只想将一个数组分散到 3 个进程中,并为每个进程中的每个值添加一个。或者,我很高兴看到如何将 2D 数组逐行发送到每个进程,并且每一行都被简单地处理。

int main(int argc, char **argv) {
    int rank; // my process ID
    int size = 3; // number of processes/nodes
    MPI_Status status;
    MPI_Init(&argc, &argv); // start MPI
    MPI_Comm_size(MPI_COMM_WORLD, &size); // initialize MPI
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    unsigned char inData[12]; // data returned after being "processed"
    unsigned char outData[12]; // buffer for receiving data
    unsigned long datasize = 12; // size of data to process
    unsigned char testData[12]; // data to be processed

    if (rank == 0) {
        // initialize data
        for (int i = 0; i < datasize; i++) {
            testData[i] = i;
            outData[i] = 0;
            inData[i] = 0;
        }
    }

    // scatter the data to the processes
    // I am not clear about the numbers sent in and out
    MPI_Scatter(&testData, 12, MPI_UNSIGNED_CHAR, &outData, 
        12, MPI_UNSIGNED_CHAR, 0, MPI_COMM_WORLD);
    MPI_Barrier(MPI_COMM_WORLD);

    // process data
    for (int i = 0; i < 4; i++) { outData[i] = outData[i] + 1; }

    MPI_Barrier(MPI_COMM_WORLD);

    // gather processed data
    MPI_Gather(&outData, 12, MPI_UNSIGNED_CHAR, &inData, 
        12, MPI_UNSIGNED_CHAR, 0, MPI_COMM_WORLD);

    //print processed data from root 
    if (rank == 0) {
        for (int i = 0; i < 12; i++) {
            printf("\n%d", inData[i]);
        }

        MPI_Finalize();
    }

    return 0;
}

【问题讨论】:

  • 我对 MPI 不太熟悉,但是……MPI_Scatter 不是所有进程都在执行吗?
  • 您不应在集体操作中使用count=12。另外,所有等级都必须调用MPI_Finalize()

标签: c mpi


【解决方案1】:

虽然您的主要错误是使用12 而不是4,但让我们一步一步来。

// int size = 3; // number of processes/nodes
int size;
...
MPI_Comm_size(MPI_COMM_WORLD, &size); // initialize MPI
assert(size == 3);

size 设置为3 没有意义。该值将被MPI_Comm_size 覆盖为实际进程数。这个数字取决于您运行 MPI 应用程序的方式(例如mpirun -np 3)。

//unsigned char outData[12]; // buffer for receiving data
unsigned char outData[4];

我们有 12 个元素和 3 个进程,每个进程 4 个元素。所以,outData 的 4 个元素就足够了。

outData[i] = 0;
inData[i] = 0;

将这些缓冲区归零是没有意义的,它们将被覆盖。

// scatter the data to the processes
// I am not clear about the numbers sent in and out
MPI_Scatter(&testData, 4 /*12*/, MPI_UNSIGNED_CHAR, &outData,
    4 /*12*/, MPI_UNSIGNED_CHAR, 0, MPI_COMM_WORLD);

我们每个进程有 4 个元素,所以数量应该是 4,而不是 12。

MPI_Barrier(MPI_COMM_WORLD);

这里不需要障碍。

MPI_Gather(&outData, 4 /*12*/, MPI_UNSIGNED_CHAR, &inData, 
    4 /*12*/, MPI_UNSIGNED_CHAR, 0, MPI_COMM_WORLD);

同样的故事,4 而不是12

MPI_Finalize();

这应该被所有进程调用。

【讨论】:

  • assert() 仅在没有 3 个 MPI 任务时中止(因为 4 是硬编码的,如果以不同数量的任务运行程序将失败)。 MPI_Scatter()MPI_Barrier() 都是障碍。例如,在MPI_Scatter() 中,根等级可能会在非根等级之前返回,甚至输入MPI_Scatter()
  • @GillesGouaillardet,没错,更正了答案。关键是这里不需要MPI_Barrier()
猜你喜欢
  • 2017-02-28
  • 2012-09-09
  • 1970-01-01
  • 1970-01-01
  • 2014-07-12
  • 1970-01-01
  • 1970-01-01
  • 2015-06-01
  • 1970-01-01
相关资源
最近更新 更多