Рассеивание больших массивов MPI4PY приводит к взаимоблокировке

Я пытаюсь разбросать массив размером (3 512 512,48,2) с типом данных двойной точности np.float64 между 3 процессами, используя Scatter():

# mpirun -np 3 python3 prog.py
import numpy as np
from mpi4py import MPI

if __name__ == "__main__":
 comm = MPI.COMM_WORLD
 nproc = comm.Get_size()
 rank = comm.Get_rank()  
 a = None

 a_split = np.empty([512,512,48,2],dtype = np.float64)


 if rank==0:

     a = np.zeros([3,512,512,48,2],dtype = np.float64)

     print(a.shape)

 comm.Barrier()

 print('Scattering')


 comm.Scatter([a, MPI.DOUBLE], a_split, root = 0)

Однако программа заходит в тупик. Из того, что я нашел отсюда

разброс и сбор mpi4py с большими массивами numpy

и тут

Вдоль какой оси делает mpi4py Scatterv функция разбивает массив numpy?

для больших массивов я должен использовать функцию Scatterv(). Итак, вот еще один код, использующий эту функцию:

# mpirun -np 3 python3 prog.py
import numpy as np
from mpi4py import MPI

if __name__ == "__main__":
    comm = MPI.COMM_WORLD
    nproc = comm.Get_size()
    rank = comm.Get_rank()  
    a = None

    a_split = np.empty([512,512,48,2],dtype = np.float64)

    size = 512*512*48*2 

    if rank==0:

        a = np.zeros([3,512,512,48,2],dtype = np.float64)

        print(a.shape)

    comm.Barrier()

    print('Scattering')

    comm.Scatterv([a,(size,size,size),(0,size,2*size),MPI.DOUBLE],a_split,root =0)

Однако это также приводит к тупику. Я также пытался отправлять массивы, используя двухточечную связь с Send(),Recv(), но это не помогает. Похоже, взаимоблокировка зависит только от размера массива - например, если я изменяю размер массивов с [512,512,48,2] на [512,10,48,2], код работает.

Может ли кто-нибудь предложить, что я могу сделать в этой ситуации?


person alcauchy    schedule 15.11.2019    source источник


Ответы (2)


Одна проблема заключается в том, что вы смешиваете np.float и MPI.DOUBLE. Рабочий сценарий может быть:

# mpirun -np 3 python3 prog.py
import numpy as np
from mpi4py import MPI
comm = MPI.COMM_WORLD
nproc = comm.Get_size()
rank = comm.Get_rank()  
a = None

a_split = np.empty([512,512,48,2],dtype = np.float)
a_split[:,:,:,:] = -666

if rank==0:
    a = np.zeros([3,512,512,48,2],dtype = np.float)
    print(a.shape)

print('Scattering')
comm.Scatter(a, a_split, root = 0)

print(a_split[1,1,1,1], a_split[-1,-1,-1,-1])

Я добавил последнюю строку печати, чтобы показать, что -np 4 будет работать, но не заполнит полностью a_split ; и -np 2 завершается с ошибкой усечения. Я предполагаю, что -np 3 было предназначено.

Если вы использовали np.float и MPI.DOUBLE было намеренно, укажите это в своем вопросе и добавьте -np, который вы используете для запуска программы.

[Изменить] Вот также версия вашего скрипта на С++, чтобы вы могли видеть, не блокируется ли он:

// mpic++ scat.cxx && mpirun -np <asmuchasyouwant> ./a.out

#include <iostream>
#include <vector>
#include <mpi.h>

int main(int argc, char** argv)
{
  MPI_Init(&argc, &argv);

  unsigned sz = 1*512*512*48*2;
  int rank, nbproc;
  std::vector<double> a;
  std::vector<double> a_split(sz);

  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  MPI_Comm_size(MPI_COMM_WORLD, &nbproc);

  if (rank == 0) {
    a.resize(nbproc * sz);
    std::fill(a.begin(), a.end(), 2.71);
  }
  else {
    std::fill(a_split.begin(), a_split.end(), -666.666);
  }  

  MPI_Scatter(a.data(), sz, MPI_DOUBLE,
              a_split.data(), sz, MPI_DOUBLE,
              0,
              MPI_COMM_WORLD
              );


  std::cout << rank << " done " << a_split[sz-1] << std::endl;

  MPI_Finalize();
}
person Demi-Lune    schedule 23.11.2019
comment
Спасибо за ответ! Смешение float и double не было преднамеренным, поэтому я отредактировал вопрос, чтобы получить правильный код. К сожалению, приведенный вами код тоже почему-то застрял на Scattering, и опять же с массивами меньшего размера код работает корректно. - person alcauchy; 25.11.2019
comment
Мой mpi4py.__version__ - это 2.0.0, и нет тупиковой ситуации. Вы используете другую версию? - person Demi-Lune; 25.11.2019
comment
Кроме того, у вас есть такой же тупик вне python, с разбросом C++? - person Demi-Lune; 25.11.2019
comment
Я пробовал код С++ - и он отлично работает, без каких-либо взаимоблокировок. Моя версия mpi4py — 3.0.2, поэтому я думаю, что попробую установить 2.0.0, чтобы проверить, работает ли она. - person alcauchy; 26.11.2019
comment
Я бы также проверил, какой libmpi.so найден вашей установкой python (кстати, вы используете Linux или Windows?) - person Demi-Lune; 26.11.2019
comment
Я использую линукс. Не могли бы вы объяснить, как мне проверить, какую версию libmpi python использует? Поиск в гугле не дал мне ответа на этот вопрос. - person alcauchy; 28.11.2019
comment
Вы можете ldd /usr/lib/python3/dist-packages/mpi4py/MPI.cpython-35m-x86_64-linux-gnu.so (изменить имя .so, оно может находиться в другом месте на вашем компьютере). Но это не на 100% (например, анаконда может перепутать путь, или у вас может быть установка в /home, virtenv...). Отказоустойчивым является (1) запуск python3 ; импортировать mpi4py как MPI ; открыть другую консоль; ps ux |grep python3 чтобы получить идентификатор процесса; grep libmpi /proc/<PID>/numa_maps - person Demi-Lune; 28.11.2019
comment
На самом деле, если у вас установлен psutil, вы также можете: import psutil ; p = psutil.Process() ; print(p.memory_maps()) отображать эту информацию numa_maps. - person Demi-Lune; 29.11.2019

Итак, в конце концов, решение было довольно простым - я обычно не выключаю свой компьютер, и похоже, что это причина, по которой он вызывает взаимоблокировку после большого количества вычислений. Простая перезагрузка решила проблему.

person alcauchy    schedule 18.03.2020