如何从MPI中的单个线程访问全局向量?
我正在使用一个库 - 特别是一个ODE求解器库 - 名为CVODE(SUNDIALS的一部分)。该库与MPI一起使用,因此多个线程并行运行。它们都运行相同的代码。每个线程将一个数据“旁边”发送给它。但我希望其中一个线程(rank = 0)在某些点打印出数据的状态。
library includes functions以便每个线程都可以访问自己的数据(本地向量)。但是没有方法可以访问全局向量。
我需要在特定时间输出所有方程的值。为此,我需要访问全局向量。任何人都知道如何获取MPI向量中的所有数据(如果可能,使用CVODE)?
例如,这是我的代码,每个线程运行
for (iout=1, tout=T1; iout <= NOUT; iout++, tout += DTOUT) {
flag = CVode(cvode_mem, tout, u, &t, CV_NORMAL);
if(check_flag(&flag, "CVode", 1, my_pe)) break;
if (my_pe == 0) PrintData(t, u);
}
...
static void PrintData(realtype t, N_Vector u) {
I want to print data from all threads in here
}
在函数f
(我正在解决的函数)中,我使用MPI_Send
和MPI_Recv
来回传递数据。但我不能在PrintData中真正做到这一点,因为其他进程已经运行。另外,我不想添加消息传递开销。我想访问PrintData
中的全局向量,然后打印出所需的内容。有可能吗?
编辑:在等待更好的答案时,我编写了每个线程将数据传递回第0个线程。我不认为这会增加太多的消息传递开销,但我仍然希望听到专家知道是否有更好的方法(我确定没有更糟糕的方法!:D)。
编辑2 :尽管angainor的解决方案确实优越,但我坚持使用我创建的解决方案。对于具有相同问题的任何人的未来参考,以下是我如何做到的基础知识:
/* Is called by all threads */
static void PrintData(realtype t, N_Vector u, UserData data) {
... declarations and such ...
for (n=1; n<=my_length; n++) {
mass_num = my_base + n;
z[mass_num - 1] = udata[n-1];
z[mass_num - 1 + N] = udata[n - 1 + my_length];
}
if (my_pe != 0) {
MPI_Send(&z, 2*N, PVEC_REAL_MPI_TYPE, 0, my_pe, comm);
} else {
for (i=1; i<npes; i++) {
MPI_Recv(&z1, 2*N, PVEC_REAL_MPI_TYPE, i, i, comm, &status);
for (n=0; n<2*N; n++)
z[n] = z[n] + z1[n];
}
... now I can print it out however I like...
return;
}
答案 0 :(得分:4)
使用MPI时,各个线程无法访问“全局” 向量。它们不是线程,它们是可以运行的进程 不同的物理计算机,因此无法直接访问全局数据。
要执行您想要的操作,您可以将矢量发送到其中一个MPI进程(您这样做)并在那里打印,或者按顺序打印本地工作器部件。使用这样的函数:
void MPI_write_ivector(int thrid, int nthr, int vec_dim, int *v)
{
int i, j;
int curthr = 0;
MPI_Barrier(MPI_COMM_WORLD);
while(curthr!=nthr){
if(curthr==thrid){
printf("thread %i writing\n", thrid);
for(i=0; i<vec_dim; i++) printf("%d\n", v[i]);
fflush(stdout);
curthr++;
MPI_Bcast(&curthr, 1, MPI_INT, thrid, MPI_COMM_WORLD);
} else {
MPI_Bcast(&curthr, 1, MPI_INT, curthr, MPI_COMM_WORLD);
}
}
}
所有MPI进程都应该同时调用它,因为内部存在屏障和广播。本质上,该过程确保所有MPI进程按顺序打印它们的向量部分,从等级0开始。数据没有搞砸,因为只有 一个进程在任何给定时间写入。
在上面的示例中,使用了Broadcast,因为它为线程打印结果的顺序提供了更大的灵活性 - 当前输出的线程可以决定,接下来是谁。您也可以跳过广播,只使用屏障
void MPI_write_ivector(int thrid, int nthr, int vec_dim, int *v)
{
int i, j;
int curthr = 0;
while(curthr!=nthr){
if(curthr==thrid){
printf("thread %i writing\n", thrid);
for(i=0; i<vec_dim; i++) printf("%d\n", v[i]);
fflush(stdout);
}
MPI_Barrier(MPI_COMM_WORLD);
curthr++;
}
}