我有一个经理和多个工人的MPI实施。 main
函数位于名为run_mpi.cpp
的文件中。它会初始化MPI并调用manager.cpp
和worker.cpp
。我想在worker.cpp
中有一些变量。我有两种方法可以做到:
当worker.cpp
函数在main
中调用变量时,我可以将变量作为参数提供给run_mpi.cpp
。
我可以使用manager.cpp
或MPI_Send
在MPI_Isend
中发送变量。
我可以在哪些条件下使用它们?他们有什么好处?
答案 0 :(得分:1)
您需要将两者视为完全独立的程序。 MPI在程序的实例(等级)之间提供通信层,但它们之间没有共享数据。假设您的主人读取带有数字列表的文件,将每个数字发送给工作人员,并且工作人员使用该数字执行某些操作。你可能会有这样的事情:
float localx;
float *x;
int rank;
int size;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,rank);
MPI_Comm_size(MPI_COMM_WORLD,size);
x=new float[size];
if (rank==0)
{
/* Typically, rank 0 is considered the master rank in a master/worker setup
Open, read, and close file.
Assume the data is read into array x, which is single precision floating point.
For ease of illustration, I'm sending to one rank at a time, but this
is better accomplished using MPI_Scatter. */
localx=x[0];
for (int i=1; i<size; i++)
{
MPI_Send(&x[i], 1, MPI_FLOAT, i, i, MPI_COMM_WORLD);
}
master(localx); // The master subroutine does whatever it needs to do
} else
{
// If the rank isn't 0, then the rank is a worker
MPI_Recv(&localx, 1, MPI_FLOAT, 0, rank, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
worker(localx);
}
delete[] x;
前三个MPI调用将初始化MPI通信环境(MPI_Init),获取当前实例的等级编号(MPI_Comm_rank)和通信器的大小(MPI_Comm_size)。 MPI_COMM_WORLD的大小是你用mpirun启动的等级数。接下来,x被分配为每个工人保留一个值。
通常,如果您使用的是主/工作模型,则将等级0视为主等级。因此,如果排名为0,我们将继续阅读该文件。作为旁注,除非您使用MPI I / O或其他并行I / O,否则只有一个级别访问文件更安全。主人将读取该文件,对于我的示例,每个工人级别应该有一个值。正如我在评论中所说,使用MPI_Scatter是一种更好的方法,但如果你是MPI的新手,我们现在就会坚持使用。首先,我将localx设置为x [0]。然后,我为每个等级调用一次MPI_Send,向每个等级发送一个x元素。一旦数据被发送出去,主等级就可以调用master(localx)并做任何需要在那里完成的事情。
如果等级编号不为0,则等级为工人。工人不会读取文件。他们将调用MPI_Recv来获取从主服务器发送的数据。工人队伍将坐在这里等待,直到数据到达。完成后,工作人员将调用worker(localx)并在那里做任何事情。
我看到人们在学习MPI时遇到的一个重大障碍是每个级别的记忆是分开的。与线程不同,绝对没有共享内存(您的应用程序可以看到,MPI实现可能会为自己设置一些内容)。通过分配点,没有任何队列具有为localx或x设置的任何值。主机读取后,只有主机知道x包含什么。发送数据后,每个工作人员等级将存储在localx中的主数据中的x中的单个值。
我提到使用MPI_Scatter更好。这是怎么做的。条件块之前和之后的所有内容都将保持不变。条件块将变为:
if (rank==0)
{
// Read the file, fill x
}
MPI_Scatter(&x[0], size, MPI_FLOAT, &localx, 1, MPI_FLOAT, 0, MPI_COMM_WORLD);
if (rank==0)
{
master(localx);
} else
{
worker(localx);
}
不同之处在于,现在,我们不是每个工人级别发送和接收一次,而是一次将数组分散到每个级别的变量中。根据您正在执行的操作,可能无法使用MPI_Scatter。这个例子很简单,你可以。