C语言 C 中如何使用 MPI_Scatter 和 MPI_Gather?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13867809/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:43:55  来源:igfitidea点击:

How are MPI_Scatter and MPI_Gather used from C?

cparallel-processingmpidistributed-computing

提问by DSF

So far, my application is reading in a txt file with a list of integers. These integers needs to be stored in an array by the master process i.e. processor with rank 0. This is working fine.

到目前为止,我的应用程序正在读取一个带有整数列表的 txt 文件。这些整数需要由主进程(即等级为 0 的处理器)存储在一个数组中。这工作正常。

Now, when I run the program I have an if statement checking whether it's the master process and if it is, I'm executing the MPI_Scattercommand.

现在,当我运行程序时,我有一个 if 语句检查它是否是主进程,如果是,我正在执行MPI_Scatter命令。

From what I understand this will subdivide the array with the numbers and pass it out to the slave processes i.e. all with rank > 0 . However, I'm not sure how to handle the MPI_Scatter. How does the slave process "subscribe" to get the sub-array? How can I tell the non-master processes to do something with the sub-array?

据我了解,这将用数字细分数组并将其传递给从属进程,即所有 rank > 0 。但是,我不确定如何处理MPI_Scatter. slave进程如何“订阅”获取子数组?我怎样才能告诉非主进程对子数组做一些事情?

Can someone please provide a simple example to show me how the master process sends out elements from the array and then have the slaves add the sum and return this to the master, which adds all the sums together and prints it out?

有人可以提供一个简单的例子来向我展示主进程如何从数组中发送元素,然后让从进程添加总和并将其返回给主进程,主进程将所有总和加在一起并打印出来?

My code so far:

到目前为止我的代码:

#include <stdio.h>
#include <mpi.h>

//A pointer to the file to read in.
FILE *fr;

int main(int argc, char *argv[]) {

int rank,size,n,number_read;
char line[80];
int numbers[30];
int buffer[30];

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);

fr = fopen ("int_data.txt","rt"); //We open the file to be read.

if(rank ==0){
printf("my rank = %d\n",rank);

//Reads in the flat file of integers  and stores it in the array 'numbers' of type int.
n=0;
while(fgets(line,80,fr) != NULL) {
  sscanf(line, "%d", &number_read);
  numbers[n] = number_read;
  printf("I am processor no. %d --> At element %d we have number: %d\n",rank,n,numbers[n]);
  n++;
}

fclose(fr);

MPI_Scatter(&numbers,2,MPI_INT,&buffer,2,MPI_INT,rank,MPI_COMM_WORLD);

}
else {
MPI_Gather ( &buffer, 2, MPI_INT, &numbers, 2, MPI_INT, 0, MPI_COMM_WORLD); 
printf("%d",buffer[0]);
}
MPI_Finalize();
return 0;
}

回答by Jonathan Dursi

This is a common misunderstanding of how operations work in MPI with people new to it; particularly with collective operations, where people try to start using broadcast (MPI_Bcast) just from rank 0, expecting the call to somehow "push" the data to the other processors. But that's not really how MPI routines work; most MPI communication requires both the sender and the receiver to make MPI calls.

这是对 MPI 中的操作如何与新手一起工作的常见误解;特别是对于集体操作,人们尝试MPI_Bcast从 rank 0开始使用广播 ( ),期望调用以某种方式将数据“推送”到其他处理器。但这并不是 MPI 例程的真正工作方式;大多数 MPI 通信需要发送方和接收方进行 MPI 调用。

In particular, MPI_Scatter()and MPI_Gather()(and MPI_Bcast, and many others) are collectiveoperations; they have to be called by allof the tasks in the communicator. All processors in the communicator make the same call, and the operation is performed. (That's why scatter and gather both require as one of the parameters the "root" process, where all the data goes to / comes from). By doing it this way, the MPI implementation has a lot of scope to optimize the communication patterns.

特别是,MPI_Scatter()MPI_Gather()(和MPI_Bcast,以及许多其他)是集体操作;它们必须被通信器中的所有任务调用。通信器中的所有处理器都进行相同的调用,并执行操作。(这就是为什么 scatter 和 gather 都需要“根”进程作为参数之一,所有数据都来自/来自那里)。通过这样做,MPI 实现有很大的空间来优化通信模式。

So here's a simple example (Updatedto include gather):

所以这是一个简单的例子(更新为包括gather):

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    int size, rank;

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    int *globaldata=NULL;
    int localdata;

    if (rank == 0) {
        globaldata = malloc(size * sizeof(int) );
        for (int i=0; i<size; i++)
            globaldata[i] = 2*i+1;

        printf("Processor %d has data: ", rank);
        for (int i=0; i<size; i++)
            printf("%d ", globaldata[i]);
        printf("\n");
    }

    MPI_Scatter(globaldata, 1, MPI_INT, &localdata, 1, MPI_INT, 0, MPI_COMM_WORLD);

    printf("Processor %d has data %d\n", rank, localdata);
    localdata *= 2;
    printf("Processor %d doubling the data, now has %d\n", rank, localdata);

    MPI_Gather(&localdata, 1, MPI_INT, globaldata, 1, MPI_INT, 0, MPI_COMM_WORLD);

    if (rank == 0) {
        printf("Processor %d has data: ", rank);
        for (int i=0; i<size; i++)
            printf("%d ", globaldata[i]);
        printf("\n");
    }

    if (rank == 0)
        free(globaldata);

    MPI_Finalize();
    return 0;
}

Running it gives:

运行它给出:

gpc-f103n084-$ mpicc -o scatter-gather scatter-gather.c -std=c99
gpc-f103n084-$ mpirun -np 4 ./scatter-gather
Processor 0 has data: 1 3 5 7 
Processor 0 has data 1
Processor 0 doubling the data, now has 2
Processor 3 has data 7
Processor 3 doubling the data, now has 14
Processor 2 has data 5
Processor 2 doubling the data, now has 10
Processor 1 has data 3
Processor 1 doubling the data, now has 6
Processor 0 has data: 2 6 10 14