У меня есть код 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 Я отредактирую в приведенном ниже решении принятый ответ.