我只是在学习OpenMPI。尝试了一个简单的MPI_Scatter示例:
#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;
}但没有像预期的那样起作用..。
我还以为会有
0 received 0
1 received 1
2 received 2 ... 但我得到的是
32609 received
1761637486 received
1 received
33 received
1601007716 received 奇怪的队伍是怎么回事?似乎和我的分散有关?另外,为什么sendcount和recvcount是一样的?一开始我想,既然我把5个元素分散到5个处理器上,那么每个处理器就会得到1个?所以我应该用:
MPI_Scatter(data, 5, MPI_INT, &num, 1, MPI_INT, 0, MPI_COMM_WORLD);但这给出了一个错误:
[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程序中看到的话,它并不是典型的?
if (rank == xxx) {更新
我注意到运行、发送和接收缓冲区的长度必须相同.这些数据应该声明如下:
int data[5][5] = { {0}, {5}, {10}, {3}, {4} };注意,列被声明为长度5,但我只初始化了1值?这里到底发生了什么?这个代码正确吗?假设我只希望每个进程只接收一个值。
发布于 2012-11-05 03:10:42
sendcount是要发送给的每个进程的元素数,而不是发送缓冲区中的元素数。MPI_Scatter将只从根进程获取通信器元素中sendcount *元素中的进程数,并将其分散到通信器中的所有进程。
因此,要向通信器中的每个进程发送一个元素(假设有5个进程),将sendcount和recvcount设置为1。
MPI_Scatter(data, 1, MPI_INT, &num, 1, MPI_INT, 0, MPI_COMM_WORLD);对可能的数据类型对有限制,它们与点对点操作相同。recvtype的类型映射应该与sendtype的类型映射兼容,也就是说,它们应该具有相同的底层基本数据类型列表。此外,接收缓冲区应该足够大以容纳接收到的消息(它可能更大,但不是更小)。在大多数简单的情况下,发送和接收端的数据类型是相同的。所以sendcount - recvcount对和sendtype - recvtype对通常是一样的.其中一个不同的例子是,在任何一方使用用户定义的数据类型时:
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,它不提供根级。相反,所有级别都接收正在收集的数据。
通信器中的所有进程都将运行该函数(尝试排除通信器中的一个进程,您将得到一个死锁)。您可以想象不同计算机上的进程盲目地运行相同的代码。然而,由于它们可能属于不同的通信组,并且具有不同的级别,因此其功能将不同地运行。每个进程都知道它是否是通信器的成员,每个进程都知道自己的级别,并且可以与根进程的级别进行比较(如果有的话),因此它们可以设置通信或相应地执行额外的操作。
https://stackoverflow.com/questions/13217149
复制相似问题