问题:
搭建MPI并行计算环境,编写
MPI程序,求和
1+2+3+…+10000。
要求:
1.使用100个进程;
2.进程0计算1+2+…+100,
进程1计算101+102+…+200.
进程99计算9901+9902
+…+10000;
3.调用计时函数,分别输出每
个进程的计算时间;
4.需使用MPI集群通信函数和同步函数
解答:
1、安装OpenMPI:
sudo apt-get update
sudo apt-get install openmpi-bin openmpi-common libopenmpi-dev
2、验证安装:
mpiexec --version
结果如下:
3、在codeblock中编写程序
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char** argv)
{
int rank, size;
int start, end, local_sum = 0, global_sum = 0;
double start_time, end_time;
// 初始化MPI环境
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
// 每个进程计算的范围
start = rank * 100 + 1;
end = start + 99;
// 记录开始时间
start_time = MPI_Wtime();
// 计算局部和
for (int i = start; i <= end; i++) {
local_sum += i;
}
// 使用MPI_Reduce计算全局和
MPI_Reduce(&local_sum, &global_sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
// 记录结束时间
end_time = MPI_Wtime();
// 输出每个进程的计算时间和局部和
printf("Process %d: Local Sum = %d, Time = %f seconds\n", rank, local_sum, end_time - start_time);
// 进程0输出全局和
if (rank == 0) {
printf("Global Sum = %d\n", global_sum);
}
// 结束MPI环境
MPI_Finalize();
return 0;
}
4、在Ubuntu命令窗口里尝试运行
先用cd切换到程序所在目录 再编译 但其实目前有问题,报错:
大概就是OpenMPI默认情况下不允许以root用户身份运行mpiexec,以提高安全性。我是又创建了个非root用户身份运行
sudo adduser newuser
然后填了两次密码,后面一直按的回车
用命令su - newuser
切换到新用户,如下图所示:
继续尝试运行,如下图:
其中-n100 是因为本程序使用100个进程运行程序
又报错:
这个错误信息表明系统中没有足够的资源(槽位)来满足你请求的100个进程。OpenMPI默认情况下会根据系统的CPU核心数来分配槽位。如果你希望在单个节点上运行100个进程,可以使用–oversubscribe选项来忽略槽位限制。
使用 --oversubscribe 选项
在运行mpiexec时,添加–oversubscribe选项:
mpiexec --oversubscribe -n 100 ./oshomework1
如下图所示重新编译运行:
成功出现运行结果啦,如下图:
下面对我一些代码进行讲解:
1、MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
在MPI(Message Passing Interface)程序中,MPI_Init、MPI_Comm_rank和MPI_Comm_size是三个常用的函数,用于初始化MPI环境、获取当前进程的标识符(rank)以及获取总进程数(size)。以下是对这些函数的详细解释:
-
MPI_Init(&argc, &argv);
功能:初始化MPI环境。
参数:
&argc:指向命令行参数数量的指针。
&argv:指向命令行参数数组的指针。
解释:
在MPI程序中,MPI_Init是第一个被调用的MPI函数。它初始化MPI环境,使得后续的MPI函数可以被调用。
通常情况下,argc和argv是从main函数的参数传递过来的。虽然这些参数在MPI程序中通常不会被使用,但MPI_Init需要它们作为参数。 -
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
功能:获取当前进程的标识符(rank)。
参数:
MPI_COMM_WORLD:MPI通信域,表示所有进程的集合。
&rank:指向存储当前进程标识符的变量的指针。
解释:
MPI_Comm_rank函数返回当前进程在指定通信域中的标识符(rank)。
MPI_COMM_WORLD是MPI预定义的通信域,包含了所有参与MPI计算的进程。
rank的值从0开始,依次递增,直到size - 1。每个进程都有一个唯一的rank值。 -
MPI_Comm_size(MPI_COMM_WORLD, &size);
功能:获取总进程数(size)。
参数:
MPI_COMM_WORLD:MPI通信域,表示所有进程的集合。
&size:指向存储总进程数的变量的指针。
解释:
MPI_Comm_size函数返回指定通信域中的总进程数。
MPI_COMM_WORLD是MPI预定义的通信域,包含了所有参与MPI计算的进程。
size表示当前MPI程序中启动的总进程数。
2、MPI_Reduce(&local_sum, &global_sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD)
MPI_Reduce是MPI(Message Passing Interface)中的一个集合通信函数,用于在所有进程中执行归约操作(reduction operation)。归约操作可以是求和、求最大值、求最小值等。MPI_Reduce将所有进程的局部数据汇总成一个全局结果,并将结果存储在指定的进程中。
参数讲解:
&local_sum:发送缓冲区,指向当前进程的局部和。
&global_sum:接收缓冲区,指向存储归约结果的变量。只有根进程(root process)会使用这个缓冲区。
1:发送缓冲区中的元素数量。
MPI_INT:发送缓冲区中元素的数据类型。
MPI_SUM:归约操作类型,这里是求和操作。
0:根进程的标识符(rank),归约结果将存储在这个进程中。
MPI_COMM_WORLD:MPI通信域,表示所有进程的集合。
详细解释:
在MPI程序中,每个进程计算自己的局部和(local_sum),然后通过MPI_Reduce函数将所有进程的局部和汇总成一个全局和(global_sum)。具体步骤如下:
每个进程计算局部和:
每个进程根据自己的rank计算从start到end的和,并将结果存储在local_sum中。
使用MPI_Reduce汇总局部和:
MPI_Reduce函数会将所有进程的local_sum汇总成一个全局和,并将结果存储在根进程(rank为0的进程)的global_sum中。
根进程输出全局和:
只有根进程(rank为0的进程)会使用global_sum,并输出全局和。