Взаимодействуйте с двоичным файлом MPI через (не-MPI) скрипт Python

Я хотел бы каким-то образом инициировать выполнение определенных функций программы MPI (написанной на C++) с помощью, например, (последовательного) скрипта Python. Этот скрипт Python должен запускать программу mpi в начале, например,

subprocess.call(['mpirun','-np', '4', 'mpibinary', 'args' ])

Мне нужно вызывать функцию этой программы MPI несколько раз, и я хочу избежать перезапуска программы для разных входных данных, так как мне приходится повторно инициализировать все мои структуры данных, что является дорогостоящим. Поэтому я подумал о внешнем запуске функции, когда программа MPI простаивает. Я думаю, что это можно сделать с помощью файлового ввода-вывода, то есть корневой ранг программы MPI наблюдает за определенным файлом в цикле while(1), и как только его содержимое изменяется, он анализирует новое содержимое, уведомляет другие ранги и вызывает функцию . Есть ли более элегантное решение моей проблемы?

Лучшим решением было бы иметь класс python, который обертывает важные функции программы C++ MPI, чтобы я мог вызывать их из python с помощью

mpiprogram.superfunction(a,b)

person thisch    schedule 14.05.2012    source источник
comment
Вместо того, чтобы отслеживать изменения в файле (что кажется хрупким), вы можете использовать именованный канал или сокет для отправки команд в корневой ранг MPI из Python.   -  person Greg Inozemtsev    schedule 15.05.2012
comment
Спасибо за ответ. Использование сокетов, конечно, более «элегантно», чем просмотр файлов, но все эти упомянутые решения требуют написания множества прокси-заглушек. Я все еще ищу что-то менее трудоемкое.   -  person thisch    schedule 15.05.2012


Ответы (1)


Возможно, самым элегантным решением было бы сделать код Python частью вашего MPI-приложения. Затем он сможет напрямую отправлять данные (через сообщения MPI) остальной части приложения MPI, поскольку оно будет его частью. Здесь есть два разных подхода:

1) Вставьте двоичный файл Python с рангом 0 в задание MPI. Чтобы исключить его из участия в коллективных операциях в mpibinary, пришлось бы сделать субкоммуникатор, исключающий ранг 0, и использовать его для всего дальнейшего коллективного общения в mpibinary. Первый шаг — это легкая часть. В Open MPI вы должны сделать:

mpirun --hostfile hosts -np 1 pythonbinary args : -np 32 mpibinary args

Это называется запуском MPMD (множество программ с несколькими данными), и он запустит одну копию pythonbinary, которая станет рангом 0, а также 32 копии mpibinary, которые станут рангом 1, рангом 2, ... до ранга 32 (33 процесса в общее). Другие реализации MPI также предоставляют очень похожие механизмы для запуска MPMD. Затем вы должны использовать MPI_Comm_split() для создания нового коммуникатора, который не включает в себя программу Python. Разделение коммуникатора является коллективной операцией. Вот почему вы должны вызывать его как в коде Python, так и в приложении C++. MPI_Comm_split() принимает "цвет" и ключ и разбивает коммуникатор на несколько субкоммуникаторов в соответствии с разными цветами. Затем процессы с одинаковым цветом сортируются на основе значения ключа. Скорее всего, вы захотите назвать это так:

в Питоне:

python_comm = mpi.mpi_comm_split(mpi.MPI_COMM_WORLD, 0, 0)

in C++:

int rank;
MPI_Comm c_comm;

MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_split(MPI_COMM_WORLD, 1, rank, &c_comm);

Использование rank в качестве ключа гарантирует, что порядок процессов в c_comm будет таким же, как и до разделения, то есть ранг 1 из MPI_COMM_WORLD станет рангом 0 в c_comm, ранг 2 станет рангом 1 и т. д.

С этого момента приложение C++ может использовать c_comm для выполнения коллективных операций, как обычно. Для связи между кодом Python и кодом C++ вам все равно придется использовать MPI_COMM_WORLD, и код Python по-прежнему будет иметь в нем ранг 0.

2) Использовать средства управления процессами MPI-2. Сначала вы запустите задание MPI, состоящее только из двоичного файла Python:

mpirun --hostfile hosts -np 1 pythonbinary args

Затем двоичный файл Python породит другой двоичный файл MPI напрямую, используя MPI_Comm_spawn() с желаемым количеством новых процессов. Вновь порожденные процессы будут иметь свои собственные MPI_COMM_WORLD, и вам не нужно будет использовать MPI_Comm_split(). Кроме того, операция порождения установит интеркоммуникатор, который позволит коду Python отправлять сообщения в другую часть приложения MPI.


В обоих случаях файл hosts будет содержать определение всех хостов выполнения, которые могут выполнять двоичные файлы MPI. Вам также потребуется использовать одну из доступных привязок Python MPI.

Обратите внимание, что вам нужно только добавить некоторые вызовы MPI в ваш скрипт Python, такие как MPI_Init, MPI_Finalize, MPI_Comm_split и соответствующие MPI_Send/MPI_Recv. Параллельно делать не надо. MPI довольно универсален, что позволяет использовать его не только для параллельной совместной работы, но и в качестве общей среды обмена сообщениями. Но обратите внимание, что привязки Python должны использовать ту же библиотеку MPI, что и остальная часть программы.

Другим решением было бы использование некоторой библиотеки очередей сообщений или пула файлов (что на самом деле является грубой реализацией MQ).

person Hristo Iliev    schedule 15.05.2012
comment
Означает ли 1) что мне нужно изменить mpibinary? Кто должен вызывать MPI_Comm_split? - person thisch; 18.05.2012
comment
К сожалению, да, и 1), и 2) требуют небольших изменений в вашем двоичном файле MPI. Подход 2) требует меньше модификаций, чем 1). Я расширил ответ, включив в него информацию о том, как вызывать MPI_Comm_split, поскольку ограничение на длину комментариев слишком жесткое. - person Hristo Iliev; 18.05.2012