карта многопроцессорного пула невероятно медленно работает ансамбль Монте-Карло python симуляций - PullRequest
2 голосов
/ 05 августа 2020

У меня есть код python, который запускает двумерное моделирование диффузии для набора параметров. Мне нужно запускать код много раз, O (1000), как в подходе Монте-Карло, каждый раз используя разные настройки параметров. Чтобы сделать это быстрее, я хочу использовать все ядра на моей машине (или кластере), чтобы каждое ядро ​​запускало один экземпляр кода.

Раньше я успешно делал это для serial fortran кодирует, написав оболочку python, которая затем использовала карту многопроцессорности (или карту звездности в случае нескольких аргументов) для вызова кода Fortan в ансамбле симуляций. Он работает очень хорошо, потому что вы l oop за 1000 симуляций, а оболочка python передает новую интеграцию в ядро, как только оно освобождается после завершения предыдущей интеграции.

Однако, Теперь, когда я настроил это на то же самое для запуска нескольких экземпляров моего кода python (вместо fortran), я обнаружил, что он невероятно медленный, намного медленнее, чем простой запуск кода 1000 раз последовательно на одном ядре. Используя системный монитор, я вижу, что одно ядро ​​работает за раз, и его загрузка никогда не превышает 10-20%, хотя, конечно, я ожидал увидеть N ядер, работающих почти на 100% (как в случае, когда я передаю задания fortran.

Я подумал, что это может быть проблема с записью, поэтому я внимательно проверил код, чтобы убедиться, что все построение отключено, и на самом деле есть нет доступ к файлу / диску в все, теперь у меня есть только один оператор печати в конце, чтобы распечатать окончательную диагностику c.

Структура моего кода такая

У меня есть основной python код в toy_diffusion_2d.py , который имеет единственный аргумент словаря с параметрами запуска в нем:

def main(arg)
loop over timesteps:
    calculation simulation over a large-grid
print the result statistic

А затем я написал сценарий «оболочки», куда я импортирую основную симуляцию code и попробуйте запустить его параллельно:

from multiprocessing import Pool,cpu_count
import toy_diffusion_2d

# dummy list of arguments
par1=[1,2,3]
par2=[4,5,6]

# make a list of dictionaries to loop over, 3x3=9 simulations in all.
arglist=[{"par1":p1,"par2":p2} for p1 in par1 for p2 in par2] 

ncore=min(len(arglist),int(cpu_count()))
with Pool(processes=ncore) as p:
    p.map(toy_diffusion_2d.main,arglist)

Выше приведен более короткий перефразированный пример, мои фактические коды длиннее, поэтому я разместил их здесь:

Основной код: http://clima-dods.ictp.it/Users/tompkins/files/toy_diffusion_2d.py

Вы можете запустить это со значениями по умолчанию, например:

python3 toy_diffusion_2d.py

Сценарий оболочки: http://clima-dods.ictp.it/Users/tompkins/files/toy_diffusion_loop.py

Вы можете запустить ансамбль из 4 элементов следующим образом:

python3 toy_diffusion_loop.py --diffK=[33000,37500] --tau_sub=[20,30]

(обратите внимание, что окончательная статистика немного отличается от каждого прогона, даже с теми же значениями, что и модель сточасти c, версия сточасти c уравнений Аллен-Кана на случай, если кто-то заинтересован, но использует дурацкий явный решатель для условия распространения).

Как я уже сказал, второй параллельный код работает, но, как я уже сказал, он очень медленный ... как будто он постоянно стробирует.

I также пробовал использовать starmap, но это не отличалось, это почти как рабочий стол позволяет запускать только один python интерпретатор за раз ...? Я потратил на это часы, я почти готов переписать код на Фортране. Я уверен, что делаю что-то действительно глупое, чтобы предотвратить параллельное выполнение.

EDIT (1): эта проблема возникает в 4.15.0-112-generi c x86_64 GNU / Linux, с Python 3.6.9

В ответ на комментарии, на самом деле я также считаю, что он отлично работает на моем ноутбуке MA C ...

EDIT (2): так что это похоже, мой вопрос был чем-то вроде дубликата нескольких других сообщений, извиняюсь! Помимо полезных ссылок, предоставленных Павлом, я также нашел эту страницу очень полезной: Импорт scipy breaks multiprocessing support в Python Я отредактирую в приведенном ниже решении принятый ответ.

1 Ответ

1 голос
/ 06 августа 2020

Предоставленный вами пример кода отлично работает на моем MacOS Catalina 10.15.6. Я могу предположить, что вы используете какой-то дистрибутив Linux, где, согласно этот ответ , может случиться так, что numpy импорт вмешивается с привязкой к ядру из-за связывания с библиотекой OpenBLAS.

Если ваш Unix поддерживает интерфейс планировщика, что-то вроде этого будет работать:

>>> import os
>>> os.sched_setaffinity(0, set(range(cpu_count)))

Другой вопрос, который дает хорошее объяснение этой проблемы , находится здесь и предлагаемое решение:

os.system('taskset -cp 0-%d %s' % (ncore, os.getpid()))

вставлено прямо перед вызовом многопроцессорной обработки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...