我的第一个想法是MPI_Scatter,应该在子句中使用发送缓冲区分配if(proc_id == 0),因为数据应该只分散一次,并且每个进程只需要发送缓冲区中的一部分数据,但是它无法正常工作。
看来发送缓冲区分配MPI_Scatter必须由所有进程执行,然后应用程序才能正常运行。
MPI_Scatter所以我想知道,既然所有进程都可以访问发送缓冲区,那么存在的哲学是什么。
任何帮助将不胜感激。
if (proc_id == 0) {
int * data = (int *)malloc(size*sizeof(int) * proc_size * recv_size);
for (int i = 0; i < proc_size * recv_size; i++) data[i] = i;
ierr = MPI_Scatter(&(data[0]), recv_size, MPI_INT, &recievedata, recv_size, MPI_INT, 0, MPI_COMM_WORLD);
}
Run Code Online (Sandbox Code Playgroud)
我想,根进程分散数据就足够了,其他进程需要做的只是接收数据。因此MPI_Scatter,我将 以及发送缓冲区定义和分配一起放入if(proc_id == 0)语句中。没有编译/运行时错误/警告,但其他进程的接收缓冲区没有收到其相应的数据部分。
你的问题不是很清楚,如果你展示一些你遇到问题的代码会更容易理解。这就是我认为您要问的问题 - 我只是猜测这一点,因为这是我在 C make 中看到 MPI 新手遇到的错误。
如果你有这样的代码:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc, char **argv) {
int proc_id, size, ierr;
int *data;
int recievedata;
ierr = MPI_Init(&argc, &argv);
ierr|= MPI_Comm_size(MPI_COMM_WORLD,&size);
ierr|= MPI_Comm_rank(MPI_COMM_WORLD,&proc_id);
if (proc_id == 0) {
data = (int *)malloc(size*sizeof(int));
for (int i=0; i<size; i++) data[i] = i;
}
ierr = MPI_Scatter(&(data[0]), 1, MPI_INT,
&recievedata, 1, MPI_INT, 0, MPI_COMM_WORLD);
printf("Rank %d recieved <%d>\n", proc_id, recievedata);
if (proc_id == 0) free(data);
ierr = MPI_Finalize();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
为什么它不起作用,为什么会出现分段错误?当然其他进程无权访问data; 这就是重点。
答案是,在非根进程中,不使用sendbuf参数( 的第一个参数)。MPI_Scatter()因此非 root 进程不需要访问data. 但是您仍然无法取消引用尚未定义的指针。因此,您需要确保所有 C 代码都是有效的。但数据在所有其他进程上可以为 NULL 或完全未定义;你只需要确保你没有意外地取消引用它。所以这工作得很好,例如:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc, char **argv) {
int proc_id, size, ierr;
int *data;
int recievedata;
ierr = MPI_Init(&argc, &argv);
ierr|= MPI_Comm_size(MPI_COMM_WORLD,&size);
ierr|= MPI_Comm_rank(MPI_COMM_WORLD,&proc_id);
if (proc_id == 0) {
data = (int *)malloc(size*sizeof(int));
for (int i=0; i<size; i++) data[i] = i;
} else {
data = NULL;
}
ierr = MPI_Scatter(data, 1, MPI_INT,
&recievedata, 1, MPI_INT, 0, MPI_COMM_WORLD);
printf("Rank %d recieved <%d>\n", proc_id, recievedata);
if (proc_id == 0) free(data);
ierr = MPI_Finalize();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果您在 C 中使用“多维数组”,并说分散矩阵的一行,那么您必须跳过一两个额外的环才能完成这项工作,但这仍然很容易。
更新:
请注意,在上面的代码中,调用了所有例程Scatter- 发送方和接收方。(实际上,发送者也是接收者)。
在消息传递范例中,发送者和接收者都必须合作才能发送数据。原则上,这些任务可以在不同的计算机上进行,也可能位于不同的建筑物中——它们之间不共享任何内容。因此,任务 1 无法将数据“放入”任务 2 内存的某些部分。(请注意,MPI2 具有“单向消息”,但即便如此,也需要发送方和接收方之间进行高度协调,因为必须留出一个窗口来将数据推入或拉出数据)。
典型的例子是发送/接收对;进程 0 向进程 3 发送数据是不够的,进程 3 还必须接收数据。
该MPI_Scatter函数包含发送和接收逻辑。根进程(这里指定为0)发出数据,所有接收者接收;每个参与的人都必须调用例程。Scatter 是MPI 集体操作的一个示例,其中通信器中的所有任务都必须调用相同的例程。其他示例包括广播、屏障、归约操作和收集操作。
如果只有进程 0 调用分散操作,您的程序将挂起,永远等待其他任务参与。