Питон многопроцессорной обработки в ЛПУ


У меня есть скрипт на python, который я написал с помощью модуля многопроцессорной обработки, для более быстрого выполнения. Расчет идет до неловкости параллельно, поэтому эффективность вычислений зависит от количества процессоров. Теперь я хотел бы использовать это в программе MPI, которая управляет вычислением MCMC на нескольких компьютерах. Этот код содержит вызов system (), который вызывает скрипт python. Тем не менее, я нахожу, что, когда он называется таким образом, эффективность увеличивается от использования многопроцессорной обработки python пропадает.

Как я могу заставить мой скрипт python сохранять прирост скорости от многопроцессорной обработки при вызове из MPI?

Вот простой пример, который аналогичен гораздо более сложным кодам, которые я хочу использовать, но показывает то же самое общее поведение. Я пишу исполняемый скрипт python под названием junk.py.
#!/usr/bin/python
import multiprocessing
import numpy as np

nproc = 3
nlen = 100000


def f(x):
    print x
    v = np.arange(nlen)
    result = 0.
    for i, y in enumerate(v):
        result += (x+v[i:]).sum()
    return result


def foo():
    pool = multiprocessing.Pool(processes=nproc)
    xlist = range(2,2+nproc)
    print xlist
    result = pool.map(f, xlist)
    print result

if __name__ == '__main__':
    foo()

Когда я запускаю это из оболочки сам по себе, используя "top", я вижу три процесса python, каждый из которых занимает 100% процессора на моей 16-ядерной машине.

node094:mpi[ 206 ] /usr/bin/time junk.py
[2, 3, 4]
2
3
4
[333343333400000.0, 333348333450000.0, 333353333500000.0]
62.68user 0.04system 0:21.11elapsed 297%CPU (0avgtext+0avgdata 16516maxresident)k
0inputs+0outputs (0major+11092minor)pagefaults 0swaps

Однако, если я вызываю это с mpirun, каждый процесс python занимает 33% процессора, и в целом он занимает примерно в три раза больше времени для запуска. Вызов с помощью-np 2 или более приводит к большему количеству процессов,но не ускоряет вычисление.

node094:mpi[ 208 ] /usr/bin/time mpirun -np 1 junk.py
[2, 3, 4]
2
3
4
[333343333400000.0, 333348333450000.0, 333353333500000.0]
61.63user 0.07system 1:01.91elapsed 99%CPU (0avgtext+0avgdata 16520maxresident)k
0inputs+8outputs (0major+13715minor)pagefaults 0swaps

(дополнительные примечания: это mpirun 1.8.1, python 2.7.3 на Linux Debian версии wheezy. Я слышал, что system() не всегда разрешена в программах MPI, но она работала для меня в течение последних пяти лет на этом компьютере. Для пример я вызвал параллельный код на основе pthread из system() в программе MPI, и он использует 100% cpu для каждого потока, как требуется. Кроме того, в случае, если вы собирались предложить запустить скрипт python в последовательном режиме и просто вызвать его на большем количестве узлов...вычисление MCMC включает фиксированное число цепочек, которые должны двигаться синхронно, поэтому вычисление, к сожалению, не может быть реорганизовано таким образом.)

1 11

1 ответ:

Mpirun OpenMPI, v1. 7 и более поздние версии , по умолчанию привязывает процессы к ядрам - то есть, когда он запускает python junk.py процесс, он связывает его с ядром, на котором он будет работать. Это нормально, и правильное поведение по умолчанию для большинства случаев использования MPI. Но здесь каждая задача MPI затем разветвляет больше процессов (через пакет многопроцессорной обработки), и эти разветвленные процессы наследуют состояние привязки своего родителя - так что все они привязаны к одному ядру, борясь между собой. (Столбец " P " в верхней части покажет вам, что все они находятся на одном процессоре)

Если вы mpirun-np 2, вы найдете два набора из трех процессов, каждый на другом ядре, каждый борется между собой.

С OpenMPI вы можете избежать этого, отключив привязку,

mpirun -np 1 --bind-to none junk.py

Или выбрать какую-то другую привязку, которая имеет смысл, учитывая окончательную геометрию вашего запуска. MPICH имеетаналогичные варианты с hydra .

Обратите внимание, что fork()ing подпроцессов с mpi не всегда безопасно или поддерживается , особенно с кластерами, работающими с InfiniBand interconnects, но mpirun/mpiexec OpenMPI предупредит вас, если это не безопасно.