MPI - 异步环通信
MPI - Asynchronous ring communication
我正在尝试实现一个简单的 MPI
程序,我在其中调用一个函数 foo()
,-n
进程在该函数上传递 n
个数组,直到传递完所有数组到所有进程(n steps
)。实现采用环形通信的形式,其中 process#0
发送到 process#2
并从 process#n-1
等接收。这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
void foo(double* X, int n,int d,int k)
{
int id, world_size;
double *array = X;
double *array_buff = malloc(n*d*sizeof(double));
MPI_Comm_rank(MPI_COMM_WORLD, &id);
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
MPI_Status status;
array[0] = id;
for(int step = 0 ; step < world_size ; step++)
{
int temp = id-step;
if(temp<0)
{
temp = world_size+temp;
}
if(array[0]!= temp)
{
printf("[%d][%d] %f (start)\n", id, step, array[0]);
}
//even processes send first while odd process receive
//first in order to avoid deadlock - achieve synchronization
MPI_Request reqsend, reqrecv;
int dst = (id+1)%world_size;
if(id%2 == 0)
{
int src = id-1;
if(id == 0)
{
src = world_size-1;
}
MPI_Isend(array, n*d, MPI_DOUBLE, dst, 0, MPI_COMM_WORLD, &reqsend);
MPI_Irecv(array_buff, n*d, MPI_DOUBLE, src, 0, MPI_COMM_WORLD, &reqrecv);
}
else
{
MPI_Irecv(array_buff, n*d, MPI_DOUBLE, id-1, 0, MPI_COMM_WORLD, &reqrecv);
MPI_Isend(array, n*d, MPI_DOUBLE, dst, 0, MPI_COMM_WORLD, &reqsend);
}
//..some array[] related work is been done here...
if(array[0]!=temp)
{
printf("[%d][%d] %f (end)\n", id, step, array[0]);
}
//update array asynchronously
MPI_Wait(&reqrecv, &status);
array = array_buff;
}
free(array);
}
为了避免死锁偶数进程先发送后接收,而奇数进程先接收后发送
初始化:array[0] = id;
目的是控制通讯是否正确进行。这就是为什么我在函数的开头和结尾使用两个打印,以观察 array[]
是否在 array = array_buff;
赋值之前更改内容(其中 array[]
取缓冲值)发生。
我得到的输出之一是:
[0][2] 1.000000 (start)
[0][2] 1.000000 (end)
[0][3] 0.000000 (start)
[0][3] 0.000000 (end)
[1][3] 1.000000 (start)
[1][3] 1.000000 (end)
[3][1] 1.000000 (end)
[3][2] 0.000000 (end)
[3][3] 3.000000 (end)
为什么 array[]
的内容在 array_buff[]
赋值之前改变了?
注意:我读到在某些 MPI 版本中,在发送完成之前使用 array[]
(Isend()
缓冲区)是不行的.但我不认为这里是这种情况,因为即使我在 Isend() Irecv()
段之后根本不使用 array[]
,程序行为仍然相同。
我已经尝试设置 tags 以匹配每个特定的发送,使用标识符值是 step 值 但我得到了僵局,我不明白为什么。我将不胜感激对此的解释。
tag = step;
问题是array = array_buff
。虽然 array[]
在第一步获得正确的值,但之后当 array_buff
在第二步、第三步等更新时,它也会更改 array[]
的内容,因为它们指向同一内存。
问题已解决:
for(int i=0; i<n*d ; i++)
{
array[i] = array_buff[i];
}
我正在尝试实现一个简单的 MPI
程序,我在其中调用一个函数 foo()
,-n
进程在该函数上传递 n
个数组,直到传递完所有数组到所有进程(n steps
)。实现采用环形通信的形式,其中 process#0
发送到 process#2
并从 process#n-1
等接收。这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
void foo(double* X, int n,int d,int k)
{
int id, world_size;
double *array = X;
double *array_buff = malloc(n*d*sizeof(double));
MPI_Comm_rank(MPI_COMM_WORLD, &id);
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
MPI_Status status;
array[0] = id;
for(int step = 0 ; step < world_size ; step++)
{
int temp = id-step;
if(temp<0)
{
temp = world_size+temp;
}
if(array[0]!= temp)
{
printf("[%d][%d] %f (start)\n", id, step, array[0]);
}
//even processes send first while odd process receive
//first in order to avoid deadlock - achieve synchronization
MPI_Request reqsend, reqrecv;
int dst = (id+1)%world_size;
if(id%2 == 0)
{
int src = id-1;
if(id == 0)
{
src = world_size-1;
}
MPI_Isend(array, n*d, MPI_DOUBLE, dst, 0, MPI_COMM_WORLD, &reqsend);
MPI_Irecv(array_buff, n*d, MPI_DOUBLE, src, 0, MPI_COMM_WORLD, &reqrecv);
}
else
{
MPI_Irecv(array_buff, n*d, MPI_DOUBLE, id-1, 0, MPI_COMM_WORLD, &reqrecv);
MPI_Isend(array, n*d, MPI_DOUBLE, dst, 0, MPI_COMM_WORLD, &reqsend);
}
//..some array[] related work is been done here...
if(array[0]!=temp)
{
printf("[%d][%d] %f (end)\n", id, step, array[0]);
}
//update array asynchronously
MPI_Wait(&reqrecv, &status);
array = array_buff;
}
free(array);
}
为了避免死锁偶数进程先发送后接收,而奇数进程先接收后发送
初始化:array[0] = id;
目的是控制通讯是否正确进行。这就是为什么我在函数的开头和结尾使用两个打印,以观察 array[]
是否在 array = array_buff;
赋值之前更改内容(其中 array[]
取缓冲值)发生。
我得到的输出之一是:
[0][2] 1.000000 (start)
[0][2] 1.000000 (end)
[0][3] 0.000000 (start)
[0][3] 0.000000 (end)
[1][3] 1.000000 (start)
[1][3] 1.000000 (end)
[3][1] 1.000000 (end)
[3][2] 0.000000 (end)
[3][3] 3.000000 (end)
为什么 array[]
的内容在 array_buff[]
赋值之前改变了?
注意:我读到在某些 MPI 版本中,在发送完成之前使用 array[]
(Isend()
缓冲区)是不行的.但我不认为这里是这种情况,因为即使我在 Isend() Irecv()
段之后根本不使用 array[]
,程序行为仍然相同。
我已经尝试设置 tags 以匹配每个特定的发送,使用标识符值是 step 值 但我得到了僵局,我不明白为什么。我将不胜感激对此的解释。
tag = step;
问题是array = array_buff
。虽然 array[]
在第一步获得正确的值,但之后当 array_buff
在第二步、第三步等更新时,它也会更改 array[]
的内容,因为它们指向同一内存。
问题已解决:
for(int i=0; i<n*d ; i++)
{
array[i] = array_buff[i];
}