gpt4 book ai didi

c++ - 简单的 MPI_Scatter 尝试

转载 作者:行者123 更新时间:2023-12-01 14:38:17 30 4
gpt4 key购买 nike

我正在学习 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

奇怪的行列是怎么回事?好像和我的散点有关?另外,为什么 sendcountrecvcount 相同?起初我想因为我将 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

不过我想知道,为什么我需要区分根进程和子进程?似乎在这种情况下,source/root 也会得到一份拷贝?另一件事是其他进程也会分散运行吗?可能不是,但为什么呢?我认为所有进程都会运行此代码,因为如果我在 MPI 程序中看到它不是典型的?

if (rank == xxx) {

更新

我注意到要运行,发送和接收缓冲区必须具有相同的长度......并且数据应该声明如下:

int data[5][5] = { {0}, {5}, {10}, {3}, {4} };

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

最佳答案

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

因此要向通信器中的每个进程发送 1 个元素(假设有 5 个进程),请将 sendcountrecvcount 设置为 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);

这是有效的,因为发送方构造了类型为 MPI_INT 的 5 个元素的消息,而每个接收方都将消息解释为 5 元素整数 vector 的单个实例。

(请注意,您在MPI_Recv中指定了要接收的最大元素数,实际接收的数量可能会更少,可以通过MPI_Get_count获取。相比之下,您在 MPI_Scatterrecvcount 中提供了预期的元素数量,因此如果接收到的消息长度不是完全和 promise 的一样。)

可能你现在知道打印出来的奇怪排名是由堆栈损坏引起的,因为 num 只能包含 1 int 但 5 intMPI_Scatter 中接收。

I am wondering though, why doing I need to differentiate between root and child processes? Seems like in this case, the source/root will also get a copy? Another thing is will other processes run scatter too? Probably not, but why? I thought all processes will run this code since its not in the typical if I see in MPI programs?

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

根进程,在 Scatter 的情况下,也会收到一段数据(来自它自己),而在 Gather 的情况下,也会将其数据包含在最终结果中。根进程也不异常(exception),除非使用“就地”操作。这也适用于所有集体沟通功能。

还有像 MPI_Allgather 这样的无根全局通信操作,其中不提供根等级。相反,所有级别都会收到正在收集的数据。

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

关于c++ - 简单的 MPI_Scatter 尝试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13217149/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com