我们只在我的计算机编程课上研究 MPI 大约一天,现在我必须为它编写一个程序。我要编写一个程序,将进程组织成两个环。
第一个环从进程 0 开始,然后继续向下一个偶数进程发送消息,最后一个进程将其消息发送回进程 0。例如,0--> 2 --> 4 --> 6 --> 8 --> 0(但它一直上升到 32 而不是 8)。下一个环也是一样,但是从进程1开始,发送到上一个关闭进程,然后返回到1。 例如,1--> 9--> 7--> 5 --> 3--> 1。
另外,我应该找到一个非常大的整数数组的最大值、最小值和平均值。我将不得不将数组分散到每个进程中,让每个进程计算一个部分答案,然后在每个人都完成后在进程 0 上一起减少答案。
最后,我将分散在各个流程中,每个流程都必须计算一个部分中出现的每个字母的数量。那部分对我来说真的没有意义。但是我们刚刚学习了非常基础的知识,所以请不要花哨的东西!这是我到目前为止所拥有的,我已经注释掉了一些东西只是为了提醒自己一些东西,所以如果有必要请忽略。
#include <iostream>
#include "mpi.h"
using namespace std;
// compile: mpicxx program.cpp
// run: mpirun -np 4 ./a.out
int main(int argc, char *argv[])
{
int rank; // unique number associated with each core
int size; // total number of cores
char message[80];
char recvd[80];
int prev_node, next_node;
int tag;
MPI_Status status;
// start MPI interface
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
sprintf(message, "Heeeelp! from %d", rank);
MPI_Barrier(MPI_COMM_WORLD);
next_node = (rank + 2) % size;
prev_node = (size + rank - 2) % size;
tag = 0;
if (rank % 2) {
MPI_Send(&message, 80, MPI_CHAR, prev_node, tag, MPI_COMM_WORLD);
MPI_Recv(&recvd, 80, MPI_CHAR, next_node, tag, MPI_COMM_WORLD, &status);
} else {
MPI_Send(&message, 80, MPI_CHAR, next_node, tag, MPI_COMM_WORLD);
MPI_Recv(&recvd, 80, MPI_CHAR, prev_node, tag, MPI_COMM_WORLD, &status);
}
cout << "* Rank " << rank << ": " << recvd << endl;
//max
int large_array[100];
rank == 0;
int max = 0;
MPI_Scatter(&large_array, 1, MPI_INT, large_array, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Reduce(&message, max, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
MPI_Finalize();
return 0;
Run Code Online (Sandbox Code Playgroud)
}
我有一个关于这个的小建议:
dest = rank + 2;
if (rank == size - 1)
dest = 0;
source = rank - 2;
if (rank == 0)
source = size - 1;
Run Code Online (Sandbox Code Playgroud)
我认为dest和source作为名称,会令人困惑(因为两者都是消息的目的地,取决于 的值rank)。使用%运算符可能有助于提高清晰度:
next_node = (rank + 2) % size;
prev_node = (size + rank - 2) % size;
Run Code Online (Sandbox Code Playgroud)
您可以选择是否接收或发送到next_node和prev_node基于价值rank % 2:
if (rank % 2) {
MPI_Send(&message, 80, MPI_CHAR, prev_node, tag, MPI_COMM_WORLD);
MPI_Recv(&message, 80, MPI_CHAR, next_node, tag, MPI_COMM_WORLD, &status);
} else {
MPI_Send(&message, 80, MPI_CHAR, next_node, tag, MPI_COMM_WORLD);
MPI_Recv(&message, 80, MPI_CHAR, prev_node, tag, MPI_COMM_WORLD, &status);
}
Run Code Online (Sandbox Code Playgroud)
这样做一两次很好,但是如果您发现代码中充斥着这些类型的开关,那么将这些环例程放在一个函数中并将下一个和上一个节点作为参数传递是有意义的。
当需要分配数字数组和字符数组时,请记住,这n / size将n % size在数组末尾留下剩余的元素,这些元素也需要处理。(可能在主节点上,只是为了简单起见。)
我添加了更多的输出语句(以及一个存储来自其他节点的消息的地方),并且简单的 ring 程序按预期工作:
dest = rank + 2;
if (rank == size - 1)
dest = 0;
source = rank - 2;
if (rank == 0)
source = size - 1;
Run Code Online (Sandbox Code Playgroud)
您可以在那里看到两个环,每个环都朝着自己的方向:
#include <iostream>
#include "mpi.h"
using namespace std;
// compile: mpicxx program.cpp
// run: mpirun -np 4 ./a.out
int main(int argc, char *argv[])
{
int rank; // unique number associated with each core
int size; // total number of cores
char message[80];
char recvd[80];
int prev_node, next_node;
int tag;
MPI_Status status;
// start MPI interface
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
sprintf(message, "Heeeelp! from %d", rank);
// cout << "Rank " << rank << ": " << message << endl;
MPI_Barrier(MPI_COMM_WORLD);
next_node = (rank + 2) % size;
prev_node = (size + rank - 2) % size;
tag = 0;
if (rank % 2) {
MPI_Send(&message, 80, MPI_CHAR, prev_node, tag, MPI_COMM_WORLD);
MPI_Recv(&recvd, 80, MPI_CHAR, next_node, tag, MPI_COMM_WORLD, &status);
} else {
MPI_Send(&message, 80, MPI_CHAR, next_node, tag, MPI_COMM_WORLD);
MPI_Recv(&recvd, 80, MPI_CHAR, prev_node, tag, MPI_COMM_WORLD, &status);
}
cout << "* Rank " << rank << ": " << recvd << endl;
//cout << "After - Rank " << rank << ": " << message << endl;
// end MPI interface
MPI_Finalize();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当需要编写更大的程序(数组 min、max、avg 和字数)时,您需要稍作更改:只rank == 0在开始时发送消息;它将向所有其他进程发送他们的拼图部分。所有其他进程将接收、执行工作,然后发回结果。rank == 0然后需要将所有这些结果整合成一个连贯的单一答案。