Проблема с использованием MPI_SENDRECV с 4 потоками

#parallel-processing #fortran #mpi

#параллельная обработка #fortran #mpi

Вопрос:

В качестве минимальной проблемы я пытаюсь отправить целое число между 4 процессорами: 0 -> 3 (rank 0 отправляет и получает от rank 3 ), 2 -> 1, 1 -> 2, 3 -> 0. Он никогда не завершает выполнение и зависает, вероятно, ожидая ответа от других потоков.

Я компилирую код с mpif90 ... и запускаю с mpiexec -np 4 ... . Ниже приведен минимальный фрагмент:

 program sendrecv
  implicit none
  include "mpif.h"
  integer :: foo, bar
  integer :: mpi_rank, mpi_size, ierr
  integer :: mpi_sendto, mpi_recvfrom
  integer :: istat(MPI_STATUS_SIZE), status, i

  call MPI_INIT(ierr)
  call MPI_COMM_SIZE(MPI_COMM_WORLD, mpi_size, ierr)
  call MPI_COMM_RANK(MPI_COMM_WORLD, mpi_rank, ierr)
  print *, "SENDING..."

  if (mpi_rank .eq. 0) then
    mpi_sendto = 3; mpi_recvfrom = 3
  else if (mpi_rank .eq. 1) then
    mpi_sendto = 2; mpi_recvfrom = 2
  else if (mpi_rank .eq. 2) then
    mpi_sendto = 1; mpi_recvfrom = 1
  else
    mpi_sendto = 0; mpi_recvfrom = 0
  end if

  foo = mpi_rank
  do i = 1, 5
    foo = mpi_rank
    call MPI_SENDRECV(foo, 1,amp;
                    amp; MPI_INTEGER, mpi_sendto, mpi_rank * 10   i,amp;
                    amp; bar, 1,amp;
                    amp; MPI_INTEGER, mpi_recvfrom, mpi_rank * 10   i,amp;
                    amp; MPI_COMM_WORLD, istat, ierr)
  end do

  print *, "...DONE"
  call MPI_FINALIZE(ierr)
end
  

Я действительно не понимаю, почему эта программа зависает, возможно, я что-то упускаю или делаю что-то действительно неправильно. Если я правильно понимаю, MPI_SENDRECV просто неблокирующий send и recv с двумя wait -s. В таком случае, скажем, если rank=0 отправляет в rank=3 , у него не должно возникнуть проблем с получением от него, верно?

Я пробовал отправлять / получать из разных потоков, т. Е. делал это:

   if (mpi_rank .eq. 0) then
    mpi_sendto = 1; mpi_recvfrom = 3
  else if (mpi_rank .eq. 1) then
    mpi_sendto = 2; mpi_recvfrom = 0
  else if (mpi_rank .eq. 2) then
    mpi_sendto = 3; mpi_recvfrom = 1
  else
    mpi_sendto = 0; mpi_recvfrom = 2
  end if
  

все еще не работает.

UPD Как было указано, теги должны быть одинаковыми при выполнении SENDRECV , однако в случае, когда этот вызов выполняется в цикле, подобные теги мало помогают (см. измененный код). Старая версия:

 call MPI_SENDRECV(foo, 1,amp;
                    amp; MPI_INTEGER, mpi_sendto, 200,amp;
                    amp; bar, 1,amp;
                    amp; MPI_INTEGER, mpi_recvfrom, 100,amp;
                    amp; MPI_COMM_WORLD, status, ierr)
  

UPD # 2 На самом деле, если кому-то интересно, я нашел обсуждение именно той проблемы, которая у меня есть, о том, почему SENDRECV -s иногда могут заходить в тупик.

Ответ №1:

Термин «поток» здесь вводит в заблуждение, вы должны говорить о задаче MPI или процессе MPI (оба эквивалентны).

Основной причиной является несоответствие тегов. Вы отправляете с тегом 200 , но получаете с тегом 100 .

Кроме того, вы должны использовать istat вместо status в качестве аргумента состояния MPI_Sendrecv() .

Вот как вы можете исправить свою программу

 call MPI_SENDRECV(foo, 1,amp;
                amp; MPI_INTEGER, mpi_sendto, 200,amp;
                amp; bar, 1,amp;
                amp; MPI_INTEGER, mpi_recvfrom, 200,amp;
                amp; MPI_COMM_WORLD, istat, ierr)
  

Комментарии:

1. Это правда, спасибо! Извините, я на самом деле имел в виду SENDRECV вызов из цикла. В этом случае одни и те же теги, похоже, не работают. :

2. Хорошо, nvm. Я нашел проблему. Это был status размер, вероятно, он был переполнен MPI_STATUS_SIZE и изменял другие переменные, которых не должно было быть в SENDRECV вызове. Использование istat сработало. Спасибо! Ублюдочный компилятор даже не потрудился предупредить меня :

3. Вероятность получения такого рода предупреждений выше, если вы use mpi вместо include 'mpif.h' . use mpi_f08 еще лучше (но требует некоторой поддержки компилятора и может потребовать также нескольких изменений кода).