Использование MPI_Irecv и MPI_Isend в цикле for

У меня проблема с MPI_Isend а также MPI_Irecv, Я работаю над матрицей смежности графа, который распределяется по строкам. Можно предположить, что каждый процессор содержит одну строку. Для каждой пары показателей (i,j) Мне нужно отправить и получить 2 целых числа. По сути, мне нужно получить некоторую другую информацию из других строк для выполнения вычислений. Я новичок в MPI, и вот он идет в бесконечный цикл, я не уверен, даже это правильный способ использования MPI_Isend или же MPI_Irecvв цикле, а также место ожидания.

Например, предположим, что у нас есть граф с 6 вершинами, и поэтому матрица смежности (adjMatrix) будет матрица 6 * 6, у нас также есть матрица 6 * 2 для некоторой другой информации, и, наконец, мы распределяем данные по 6 процессорам. Следовательно:

          |0  20 16 0  6  0 |      |0  1|
|20 0  0  19 0  6 |      |1  1|
addMatrix=|16 0  0  0  12 0 |    M=|2  1|
|0  19 0  0  0  12|      |3  1|
|6  0  12 0  0  9 |      |0  0|
|0  6  0  12 9  0 |      |1  0|

Распределим матрицы следующим образом:

P0:       |0  20 16 0  6  0 |      |0  1|

P1:       |20 0  0  19 0  6 |      |1  1|

P2:       |16 0  0  0  12 0 |      |2  1|

P3:       |0  19 0  0  0  12|      |3  1|

P4:       |6  0  12 0  0  9 |      |0  0|

P5:       |0  6  0  12 9  0 |      |1  0|

Теперь каждый процессор должен обновить свою часть adjMatrix, Для этого им нужна информация из некоторой части матрицы M, что есть в других процессорах. Например, чтобы P0 индекс обновлений (0,1) который 20, он должен иметь доступ к строке 1 матрицы M который {1,1}, Следовательно:

P1 должен отправить MLocal[0][0]=1 а также MLocal[0][1]=1 в P0 в котором P0
получает их как M_j0 а также M_j1соответственно.

А также

P0 должен отправить MLocal[0][0]=0 а также MLocal[0][1]=1 в P1 в котором P1
получает их как M_j0 а также M_j1соответственно.

    for(int i=0;i<rows;i++){
for (int j=0; j<n; j++)
{
int M_j0,M_j1;
MPI_Isend(&MLocal[i][0], 1, MPI_INT, j, my_rank+i*n+j+0, MPI_COMM_WORLD, &send_request0);
MPI_Isend(&MLocal[i][1], 1, MPI_INT, j, my_rank+i*n+j+1, MPI_COMM_WORLD, &send_request1);
MPI_Irecv(&M_j0, 1, MPI_INT, j, my_rank+i*n+j+0, MPI_COMM_WORLD, &recv_request0);
MPI_Irecv(&M_j1, 1, MPI_INT, j, my_rank+i*n+j+1, MPI_COMM_WORLD, &recv_request1);
//MPI_Wait(&send_request0, &status);
//MPI_Wait(&send_request1, &status);
MPI_Wait(&recv_request0, &status);
MPI_Wait(&recv_request1, &status);

// Do something ...
}
}

Затем с предложением GillesGouaillardet я изменил это 4 MPI_Isend а также MPI_Irecv чтобы:

    MPI_Sendrecv(&MoatsLocal[i][0], 1, MPI_INT, j, my_rank+i*n+j+0, &M_j0,1, MPI_INT, my_rank, my_rank+i*n+j+0, MPI_COMM_WORLD, &status);
MPI_Sendrecv(&MoatsLocal[i][1], 1, MPI_INT, j, my_rank+i*n+j+1, &M_j1,1, MPI_INT, my_rank, my_rank+i*n+j+1, MPI_COMM_WORLD, &status);

Но тем не менее, это идет в бесконечный цикл.

ОБНОВИТЬ:

Я обновил код, часть проблемы была из-за ранжирования процессоров и соответствия тегов. Я исправил эту часть, но тем не менее, она имела склонность к тупику, что, я думаю, я знаю, в чем проблема. И, возможно, не сможет решить это. Если бы у меня было достаточное количество процессоров, чтобы распределить каждую строку к процессору, то есть n = p, проблем не было бы. Но проблема в том, где число процессоров меньше, чем nтогда поток не проходит через главную диагональ. Я объясню это на примере, предположим, что у нас 4 процессора и n=6, Предположим, что это распределение:

P0:       |0  20 16 0  6  0 |      |0  1|

P1:       |20 0  0  19 0  6 |      |1  1|
|16 0  0  0  12 0 |      |2  1|

P2:       |0  19 0  0  0  12|      |3  1|

P3:       |6  0  12 0  0  9 |      |0  0|
|0  6  0  12 9  0 |      |1  0|

Это то, что происходит через цикл.

Первая итерация:

P0 отправлять и получать в / из P1 информацию для (0,1): «20» и ждать (сделано)

P1 отправлять и получать в / из P0 информацию для (1,0): «20» и ждать (сделано)

P2 отправлять и получать в / из P1 информацию для (3,1): «19» и ждать

P3 отправлять и получать в / из P0 информацию для (4,1): «6» и ждать

Вторая итерация:

P0 отправлять и получать в / из P1 информацию для (0,2): «16» и ждать

P1 отправлять и получать в / из P2 информацию для (1,3): «19» и ждать (сделано)

P2 был в ожидании P1 (3,1): «19», затем просто получил его и сделал!

P3 ожидает P0 для (4,1): «6» и ждет

Третья итерация:

P0 ожидает P1 для (0,2): «16»

P1 отправлять и получать в / из P3 информацию для (1,5): «19» и ждать

P2 отправлять и получать в / из P3 информацию для (3,5): «12» и ждать

P3 ожидает P0 для (4,1): «6»

Четвертая итерация:

P0 ожидает P1 для (0,2): «16»

P1 ожидает P3 для (1,5): «19»

P2 ожидает P3 для (3,5): «12»

P3 ожидает P0 для (4,1): «6»

Теперь все ждут друг друга, я не думаю, что есть какой-то способ решить это. Решение, которое предложил ptb, может сработать, я попробую это.

Тем не менее, любая другая идея приветствуется!

0

Решение

Есть несколько проблем с кодом, который вы разместили

  1. Каждый процессор будет проходить rows, Однако в вашем описании строки распределены между процессорами, так что это, вероятно, ошибка.
  2. Назначение и источники для отправки и получения идентичны. Так что если вы рассмотрите случай, когда j=0, MPI_Isend (…, j, …) означает, что каждый ранг будет отправлять что-то в корневой процесс. Затем следует вызов MPI_IRecv (…, j, …), MPI_Wait, что означает, что каждый процесс будет ожидать отправки от корневого процесса, который никогда не приходит.
  3. Вызов MPI_SendRecv имеет ту же фундаментальную проблему

Проблема в том, что вам нужны ваши вызовы send и recv, чтобы соответствовать. Один из способов сделать это (не обязательно самый производительный) состоит в том, чтобы опубликовать все ваши посылки через MPI_Isend в цикле, а затем использовать MPI_Probe, MPI_Recv для обработки каждого ранга recvs (так как количество recvs — это количество посылок, которое вы точно знаете, как много). Пример псевдокода:

int send_count = 0;
for (int j=0; j<n; j++) {
if (matrix_entry[j] != 0) {
call MPI_Isend(M_local, 2, MPI_INT, j, 0, ...)
send_count++;
}
}
while (send_count) {
MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, comm, status)
/* get source from status and then call recv */
MPI_Recv(M_j01, 2, MPI_INTEGER, status(MPI_SOURCE), ...)
/* Do something with M_j01 */
send_count--;
}
1

Другие решения

Несколько небольших советов:

Вы всегда должны помнить, что каждый процесс независим. Нет синхронизации между процессами (ожидайте, если вы установите MPI_Barrier).

Я действительно не понимаю ваш цикл по строкам (действительно ли строки = 6?)

Тогда все процессы выполняют код ….
Это означает:
P0,1,2,3,4,5,6 Вызовы ваши sendrecv, все они делают это 6 раз, так как эти вызовы находятся в цикле …

Напоследок: какой будет обычный размер матрицы?
Это очень плохая идея — отправлять множество очень маленьких сообщений.

Вы должны разработать свой алгоритм следующим образом:
1) Определите, какие данные нужны PX процесса для обновления всех его столбцов.
2) осуществлять связь, которая собирает эти данные для всех процессов
3) Выполните обновление.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector