我正在编写代码,其中每个处理器必须与多个处理器进行交互。
Ex:我有12个处理器,所以处理器0必须通信说1,2,10和9.让我们称它们为处理器0的邻居。同样我有 处理器1必须与5,3进行通信。 处理器2必须与5,1,0,10,11通信 等等。 数据流是2种方式,即处理器0必须将数据发送到1,2,10和9,并且还从它们接收数据。 此外,标签计算没有问题。 我创建了一个代码如下:
for(all neighbours)
{
store data in vector<double> x;
MPI_Send(x)
}
MPI_BARRIER();
for(all neighbours)
{
MPI_Recv(x);
do work with x
}
现在我针对不同大小的x和不同的邻居排列测试这个算法。代码适用于某些人,但不适用于其他人,它只是解决死锁问题。 我也尝试过:
for(all neighbours)
{
store data in vector<double> x;
MPI_ISend(x)
}
MPI_Test();
for(all neighbours)
{
MPI_Recv(x);
do work with x
}
结果是一样的,虽然死因在结果中由NaN重新复制,因为MPI_Test()告诉我某些MPI_Isend()操作没有完成,它会立即跳转到MPI_Recv()。
任何人都可以指导我这件事,我错了什么?或者我的基本方法本身是不正确的?
编辑:我附上了代码段,以便更好地理解问题。我基本上致力于并行化非结构化3D-CFD求解器
我附上了其中一个文件,但有一些解释。我不是广播,我正在循环访问父处理器的邻居以通过接口发送数据(这可以定义为两个接口之间的边界)。
所以,如果说我有12个处理器,并说处理器0必须通信说1,2,10和9.所以0是父处理器,1,2,10和9是它的邻居。
由于文件太长而且是解算器的一部分,为了简单起见,我只保留了MPI函数。
void Reader::MPI_InitializeInterface_Values() {
double nbr_interface_id;
Interface *interface;
MPI_Status status;
MPI_Request send_request, recv_request;
int err, flag;
int err2;
char buffer[MPI_MAX_ERROR_STRING];
int len;
int count;
for (int zone_no = 0; zone_no<this->GetNumberOfZones(); zone_no++) { // Number of zone per processor is 1, so basically each zone is an independent processor
UnstructuredGrid *zone = this->ZoneList[zone_no];
int no_of_interface = zone->GetNumberOfInterfaces();
// int count;
long int count_send = 0;
long int count_recv = 0;
long int max_size = 10000; // can be set from test case later
int max_size2 = 199;
int proc_no = FlowSolution::processor_number;
for (int interface_no = 0; interface_no < no_of_interface; interface_no++) { // interface is defined as a boundary between two zones
interface = zone->GetInterface(interface_no);
int no_faces = interface->GetNumberOfFaces();
if (no_faces != 0) {
std::vector< double > Variable_send; // The vector which stores the data to be sent across the interface
std::vector< double > Variable_recieve;
int total_size = FlowSolution::VariableOrder.size() * no_faces;
Variable_send.resize(total_size);
Variable_recieve.resize(total_size);
int nbr_proc_no = zone->GetInterface(interface_no)->GetNeighborZoneId(); // neighbour of parent processor
int j = 0;
nbr_interface_id = interface->GetShared_Interface_ID();
for (std::map<VARIABLE, int>::iterator iterator = FlowSolution::VariableOrder.begin(); iterator != FlowSolution::VariableOrder.end(); iterator++) {
for (int face_no = 0; face_no < no_faces; face_no++) {
Face *face = interface->GetFace(face_no);
int owner_id = face->Getinterface_Original_face_owner_id();
double value_send = zone->GetInterface(interface_no)->GetFace(face_no)->GetCell(owner_id)->GetPresentFlowSolution()->GetVariableValue((*iterator).first);
Variable_send[j] = value_send;
j++;
}
}
count_send = nbr_proc_no * max_size + nbr_interface_id; // tag for data to be sent
err2 = MPI_Isend(&Variable_send.front(), total_size, MPI_DOUBLE, nbr_proc_no, count_send, MPI_COMM_WORLD, &send_request);
}// end of sending
} // all the processors have sent data to their corresponding neighbours
MPI_Barrier(MPI_COMM_WORLD);
for (int interface_no = 0; interface_no < no_of_interface; interface_no++) { // loop over of neighbours of the current processor to receive data
interface = zone->GetInterface(interface_no);
int no_faces = interface->GetNumberOfFaces();
if (no_faces != 0) {
std::vector< double > Variable_recieve; // The vector which collects the data sent across the interface from
int total_size = FlowSolution::VariableOrder.size() * no_faces;
Variable_recieve.resize(total_size);
count_recv = proc_no * max_size + interface_no; // tag to receive data
int nbr_proc_no = zone->GetInterface(interface_no)->GetNeighborZoneId();
nbr_interface_id = interface->GetShared_Interface_ID();
MPI_Irecv(&Variable_recieve.front(), total_size, MPI_DOUBLE, nbr_proc_no, count_recv, MPI_COMM_WORLD, &recv_request);
/* Now some work is done using received data */
int j = 0;
for (std::map<VARIABLE, int>::iterator iterator = FlowSolution::VariableOrder.begin(); iterator != FlowSolution::VariableOrder.end(); iterator++) {
for (int face_no = 0; face_no < no_faces; face_no++) {
double value_recieve = Variable_recieve[j];
j++;
Face *face = interface->GetFace(face_no);
int owner_id = face->Getinterface_Original_face_owner_id();
interface->GetFictitiousCell(face_no)->GetPresentFlowSolution()->SetVariableValue((*iterator).first, value_recieve);
double value1 = face->GetCell(owner_id)->GetPresentFlowSolution()->GetVariableValue((*iterator).first);
double face_value = 0.5 * (value1 + value_recieve);
interface->GetFace(face_no)->GetPresentFlowSolution()->SetVariableValue((*iterator).first, face_value);
}
}
// Variable_recieve.clear();
}
}// end of receiving
}
答案 0 :(得分:0)
使用问题陈述:
如果你只是运行一个12步程序,你可以让生活更轻松:
每个步骤都可以实现为MPI_Scatterv(一些sendcounts将为零),然后是MPI_Gatherv。总共有22个电话,你已经完成了。
答案 1 :(得分:0)
可能有几种可能的死锁原因,所以你必须更加具体,e。 G。标准说:&#34;当使用标准发送操作时,可能会发生死锁情况,因为缓冲区空间不可用,两个进程都被阻塞。&#34;
你应该同时使用Isend和Irecv。一般结构应该是:
MPI_Request req[n];
MPI_Irecv(..., req[0]);
// ...
MPI_Irecv(..., req[n-1]);
MPI_Isend(..., req[0]);
// ...
MPI_Isend(..., req[n-1]);
MPI_Waitall(n, req, MPI_STATUSES_IGNORE);
答案 2 :(得分:0)
通过使用AllGatherV,问题可以解决。我所做的就是发送计数,使发送计数只有我想要与之通信的处理器。其他处理器有0个发送计数。 这解决了我的问题
谢谢大家的答案!