我是 MPI 初学者。我有一个大型数组 gmat
(类型为 double,尺寸为 1x14000000),它是预先计算并存储在二进制文件中的。它将使用大约 100 MB 的内存(14000000 x8 字节/1024/1024)。我想编写一个 MPI 代码,它将对该数组进行一些计算(例如,将 gmat
的所有元素乘以进程的等级数)。此数组 gmat
本身在运行时保持不变。
代码应该是这样的
#include <iostream>
#include "mpi.h"
double* gmat;
long int imax;
int main(int argc, char* argv[])
{
void performcomputation(int rank); // this function performs the computation and will be called by all processes
imax=atoi(argv[1]); // user inputs the length of gmat
MPI::Init();
rank = MPI::COMM_WORLD.Get_rank();
size = MPI::COMM_WORLD.Get_size(); //i will use -np 16 = 4 processors x 4 cores
if rank==0 // read the gmat array using one of the processes
{
gmat = new double[imax];
// read values of gmat from a file
// next line is supposed to broadcast values of gmat to all processes which will use it
MPI::COMM_WORLD.Bcast(&gmat,imax,MPI::DOUBLE,1);
}
MPI::COMM_WORLD.Barrier();
performcomputation(rank);
MPI::Finalize();
return 0;
}
void performcomputation(int rank)
{
int i;
for (i=0;i <imax; i++)
cout << "the new value is" << gmat[i]*rank << endl;
}
我的问题是,当我使用 16 个进程 (-np 16) 运行此代码时,所有进程的 gmat 是否相同?我的意思是,代码会在内存中使用 16 x 100 MB 来为每个进程存储 gmat 还是仅使用 100 MB 因为我已将 gmat 定义为全局?而且我不希望不同的进程从文件中单独读取 gmat,因为读取这么多数字需要时间。什么是更好的方法来做到这一点?谢谢。
最佳答案
首先,请不要使用 MPI C++ 绑定(bind)。这些在 MPI-2.2 中被弃用,然后在 MPI-3.0 中被删除,因此不再是规范的一部分,这意味着 future 的 MPI 实现甚至不需要提供 C++ 绑定(bind),如果他们这样做的话, 它们可能会在界面外观上有所不同。
也就是说,您的代码包含一个非常常见的错误:
if rank==0 // read the gmat array using one of the processes
{
gmat = new double[imax];
// read values of gmat from a file
// next line is supposed to broadcast values of gmat to all processes which will use it
MPI::COMM_WORLD.Bcast(&gmat,imax,MPI::DOUBLE,1);
}
这行不通,因为这里有四个错误。首先,gmat
只分配在 rank 0 而没有分配在 others ranks,这不是你想要的。其次,你给 Bcast
指针 gmat
的地址而不是它指向的数据的地址(即你不应该使用 &
运营商)。您还从等级 0
进行广播,但将 1
作为广播根参数。但最重要的错误是 MPI_BCAST
是一个集体通信调用,所有 等级都需要使用相同的 root
参数值来调用它为了让它成功完成。正确的代码(使用 C 绑定(bind)而不是 C++ 绑定(bind))是:
gmat = new double[imax];
if (rank == 0)
{
// read values of gmat from a file
}
MPI_Bcast(gmat, imax, MPI_DOUBLE, 0, MPI_COMM_WORLD);
// ^^^^ ^^^
// no & root == 0
每个级别都有自己的 gmat
拷贝。最初所有值都是不同的(例如随机或全零,取决于内存分配器)。广播后,所有拷贝将与等级 0 的 gmat
拷贝相同。调用 performcomputation()
后,每个拷贝将再次不同,因为每个等级都会乘以元素具有不同数字的 gmat
。您的问题的答案是:代码将在每个等级中使用 100 MiB,因此总共使用 16 x 100 MiB。
MPI 处理分布式内存 - 进程不共享变量,无论它们是本地变量还是全局变量。共享数据的唯一方法是使用 MPI 调用,如点对点通信(例如 MPI_SEND
/MPI_RECV
)、集体调用(例如 MPI_BCAST
) 或单向通信(例如 MPI_PUT
/MPI_GET
)。
关于c++ - 如何在 MPI 中使用共享的全局数据集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18937359/