首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >简单的MPI_Scatter尝试

简单的MPI_Scatter尝试
EN

Stack Overflow用户
提问于 2012-11-04 08:25:47
回答 1查看 9.1K关注 0票数 3

我只是在学习OpenMPI。尝试了一个简单的MPI_Scatter示例:

代码语言:javascript
复制
#include <mpi.h>

using namespace std;

int main() {
    int numProcs, rank;

    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    int* data;
    int num;

    data = new int[5];
    data[0] = 0;
    data[1] = 1;
    data[2] = 2;
    data[3] = 3;
    data[4] = 4;
    MPI_Scatter(data, 5, MPI_INT, &num, 5, MPI_INT, 0, MPI_COMM_WORLD);
    cout << rank << " recieved " << num << endl; 

    MPI_Finalize();
    return 0;
}

但没有像预期的那样起作用..。

我还以为会有

代码语言:javascript
复制
0 received 0
1 received 1 
2 received 2 ... 

但我得到的是

代码语言:javascript
复制
32609 received 
1761637486 received 
1 received 
33 received 
1601007716 received 

奇怪的队伍是怎么回事?似乎和我的分散有关?另外,为什么sendcountrecvcount是一样的?一开始我想,既然我把5个元素分散到5个处理器上,那么每个处理器就会得到1个?所以我应该用:

代码语言:javascript
复制
MPI_Scatter(data, 5, MPI_INT, &num, 1, MPI_INT, 0, MPI_COMM_WORLD);

但这给出了一个错误:

代码语言:javascript
复制
[JM:2861] *** An error occurred in MPI_Scatter
[JM:2861] *** on communicator MPI_COMM_WORLD
[JM:2861] *** MPI_ERR_TRUNCATE: message truncated
[JM:2861] *** MPI_ERRORS_ARE_FATAL: your MPI job will now abort

我想知道,为什么我需要区分根进程和子进程?在这种情况下,源/根也会得到一个副本吗?另一件事是其他进程也会运行分散吗?可能不是,但为什么?我认为所有进程都会运行这段代码,因为如果我在MPI程序中看到的话,它并不是典型的?

代码语言:javascript
复制
if (rank == xxx) {

更新

我注意到运行、发送和接收缓冲区的长度必须相同.这些数据应该声明如下:

代码语言:javascript
复制
int data[5][5] = { {0}, {5}, {10}, {3}, {4} };

注意,列被声明为长度5,但我只初始化了1值?这里到底发生了什么?这个代码正确吗?假设我只希望每个进程只接收一个值。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-11-05 03:10:42

sendcount是要发送给的每个进程的元素数,而不是发送缓冲区中的元素数。MPI_Scatter将只从根进程获取通信器元素中sendcount *元素中的进程数,并将其分散到通信器中的所有进程。

因此,要向通信器中的每个进程发送一个元素(假设有5个进程),将sendcountrecvcount设置为1。

代码语言:javascript
复制
MPI_Scatter(data, 1, MPI_INT, &num, 1, MPI_INT, 0, MPI_COMM_WORLD);

对可能的数据类型对有限制,它们与点对点操作相同。recvtype的类型映射应该与sendtype的类型映射兼容,也就是说,它们应该具有相同的底层基本数据类型列表。此外,接收缓冲区应该足够大以容纳接收到的消息(它可能更大,但不是更小)。在大多数简单的情况下,发送和接收端的数据类型是相同的。所以sendcount - recvcount对和sendtype - recvtype对通常是一样的.其中一个不同的例子是,在任何一方使用用户定义的数据类型时:

代码语言:javascript
复制
MPI_Datatype vec5int;

MPI_Type_contiguous(5, MPI_INT, &vec5int);
MPI_Type_commit(&vec5int);

MPI_Scatter(data, 5, MPI_INT, local_data, 1, vec5int, 0, MPI_COMM_WORLD);

这是因为发送方构建5个MPI_INT类型元素的消息,而每个接收方将消息解释为一个5元素整数向量的单个实例。

(请注意,您指定了要在MPI_Recv中接收的元素的最大数量,实际接收的数量可能较少,这可以由MPI_Get_count获得。相反,您提供了在recvcount of MPI_Scatter中接收到的预期元素数,因此,如果接收到的消息长度与承诺的不完全相同,则会引发错误。)

您可能现在已经知道,打印出来的奇怪级别是由堆栈损坏引起的,因为num只能包含一个int,但是在MPI_Scatter中接收到5个int

我想知道,为什么我需要区分根进程和子进程?在这种情况下,源/根也会得到一个副本吗?另一件事是其他进程也会运行分散吗?可能不是,但为什么?我认为所有进程都会运行这段代码,因为如果我在MPI程序中看到的话,它并不是典型的?

在诸如分散和收集等某些操作中,有必要区分通信器中的根进程和其他进程(它们不是根进程的子进程,因为它们可以在单独的计算机中),因为它们是集体通信(组通信),但具有单个源/目的地。因此,单个源/目标(奇怪的输出)被称为根。所有进程都必须知道源/目标(根进程)才能正确设置、发送和接收。

在散布的情况下,根进程也将接收(来自自身的)数据,在收集的情况下,也将在最终结果中包含其数据。根进程不例外,除非使用“就位”操作。这也适用于所有集体交流职能。

还有一些没有根的全局通信操作,比如MPI_Allgather,它不提供根级。相反,所有级别都接收正在收集的数据。

通信器中的所有进程都将运行该函数(尝试排除通信器中的一个进程,您将得到一个死锁)。您可以想象不同计算机上的进程盲目地运行相同的代码。然而,由于它们可能属于不同的通信组,并且具有不同的级别,因此其功能将不同地运行。每个进程都知道它是否是通信器的成员,每个进程都知道自己的级别,并且可以与根进程的级别进行比较(如果有的话),因此它们可以设置通信或相应地执行额外的操作。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13217149

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档