Python всегда впечатляюще быстр при обработке больших наборов данных. Как только код начинает работать, остальное время вы тратите на виноватую прокрутку экрана телефона.
MPI(Message Passing Interface)дасуществоватьпараллельный Расчет,существовать Передача информации между различными процессамииз Стандартное решение。mpi4py
это егоpythonВерсия。
В Интернете есть много обучающих материалов о том, как пройтиmpi4py
выполнитьсинхронныйработать относительно независимоpythonкод。существоватьсерверначальствобегатькодизособенно полезно, когда。
Прежде чем мы начнем, необходимо понять две основные концепции:
node,Трансляцию обычно называют серверным узлом. мое понимание,узел,Можно рассматривать как персональный компьютер。каждыйnode(за компьютер)Может быть несколькоcore(ядерный)。Например, вы, возможно, слышали,Программа работает на 12 узлах,Каждый узел выполняет 128 задач. то есть,Эта программасинхронно запускается
индивидуальныйcoresначальство。может быть, одининдивидуальныйcoreвозвращаться Может быть несколькоCPU.
Например, в простом примере, показанном ниже, всего имеется 12 параллельных задач. У нас он работает на двух узлах, поэтому на каждом узле нужно выполнить 6 задач. При этом мы указываем, что каждый узел вызывает только 4 ядра (поскольку все ядра делят память поровну, если все ядра вызываются одновременно, памяти, доступной для каждого ядра, может не хватить для одной задачи). В этом случае 6 задач распределяются по 4 ядрам, а некоторые ядра нужно запускать дважды, например [2,2,1,1]. См. рисунок ниже.
img
позволитьpythonкодпроходитьmpi4py
параллельный,На самом деле мало что нужно менять. Основная логика,Получить индекс всех узлов и всех ядер системы.,Таким образом, вы получите индекс всех «каналов», которыми может управлять синхронный,Тогда по общему количеству "каналов",Разделите задачи, которые необходимо выполнить, на несколько групп.,Наконец, назначьте разные группы разным «каналам» и запускайте их отдельно.
mpi4py
при условии, что ты хочешьпараллельный Операцияизpythonкод Вызов“python_mpi4py.py“,этотиндивидуальныйкоддаодининдивидуальныйможет быть независимымсуществоватьодин台电脑начальство(узел)начальствоосуществлятьизкод。Следующие пояснения предназначены только для лучшего понимания.(можно пропустить),На самом деле, после того, как я разобрался в коде, осталось не так уж много мест, которые можно было бы изменить.
num
обозначениеэтотиндивидуальныйpythonизосновная частькодбегатьсуществоватьгдеиндивидуальныйnodeначальство。действительныйначальство Используется только для вывода информации。t1
иt2
обозначение,во всех задачах,текущийnodeначальство(node index дляnum
)Запустите первыйt1-t2
шаг。У нас есть всего12шаг (кодсерединаperiods=12)задача,И мы указываем два узла для выполнения этих 12-шаговых задач.,Итак, в настоящее времяnodeЗапускайте только часть всех задач(Нет.t1-t2
шаг)。потому чтодлявызов2индивидуальныйnodes,python_mpi4py.py будет запущен дважды.,каждый раз принимай разныеt1
иt2
,Эти два шага суммируются для запуска всех t.rank
иsize
даmpi4pyочень важное понятие в。сейчассуществовать Вернемся к спискуиндивидуальныйnode,Вотrank
можно рассматривать какдаэтотиндивидуальныйnodeВсе вcoreизindex。например,Указываем вызывать 4 ядра,Чтоrankиз Стоило тогодаодининдивидуальныйlistrank=[0,1,2,3]
。size
(кодсередина写作npro
)даполучатьизcoresизобщий,здесьsize=4
。Вот Объяснение навернякада Чрезмерное упрощение。Но что-то вроде этого。steps_global[t1:t2]
)。этотиндивидуальныйsub- groupвозвращаться需要进одиншаг Распространено по-разномуизcores(кодсерединаизlist_all_pros
).#%%
import sys
import numpy as np
import mpi4py
import time as pytime
import pandas as pd
# get the number of the node, and the range of the steps [t1:t2] that runs on this node
num = int(sys.argv[1])
t1 = int(sys.argv[2])
t2 = int(sys.argv[3])
# example of all the steps that need to be run on all the nodes
time = pd.date_range('2020-01-01', periods=12, freq='H')
# the steps that need to be run on this node
steps_global = np.arange(time.size)
steps = steps_global[t1:t2] # sub-group for this node
# === mpi4py ===
try:
from mpi4py import MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
npro = comm.Get_size()
except:
print('::: Warning: Proceeding without mpi4py! :::')
rank = 0
npro = 1
list_all_pros = [0]*npro # sub-sub-groups for all the cores
for nn in range(npro):
list_all_pros[nn] = steps[nn::npro]
steps = list_all_pros[rank]
pytime.sleep(0.1*rank) # to make sure the print statements are in order
# use mpi4py here
for kk, step in enumerate(steps):
print(f'node: {num}: kk = {kk+1}/{steps.size}, step = {step}')
print(f'{time[step]}')
В приведенном выше коде мы сжали исходный 12-шаговый цикл максимум до 2-шагового цикла. Конечно, простор для фантазии еще есть.
要бегатьначальстволапшаиз Включатьmpi4py
изкод,Самый простойиз可以один句bash
Просто закажи:
mpirun -np 4 python -u python_mpi4py.py 1 2
Вышеупомянутая команда -np 4обозначение4индивидуальныйядерный同时бегать。Затем1Укажите индекс узла,2 и
Конечно, на сервере обычно сначала нужно выделить ресурсы. ресурс,Затем写одининдивидуальный Скрипт(имядляsubmit_python_mpi4py.sh)提交后台бегатькод:
#!/bin/bash
#SBATCH --job-name=parallel
#SBATCH --time=00:01:00
#SBATCH --partition=compute
#SBATCH --nodes=1
#SBATCH --ntasks=4
#SBATCH --account=*****
mpirun -np 4 python -u python_mpi4py.py $1 $2 $3
для лучшего понимания,Здесь приведенный выше код bash отправляется несколько раз через код Python.,То есть подать заявку на несколько узлов. Это позволяет более непосредственно контролировать, какие задачи на каком узле выполняются. например,изменить ситуациюиз Модельсуществоватьдругойизnodesначальствобегать。этотиндивидуальныйpython文件我们имядляmaster_submitter.py
#!/usr/bin/env python
#%%
import os
import numpy as np
#%%
nsteps = 12
npar = 6
njobs = int(nsteps/npar) # 2 nodes
#%%
for kk in range(njobs): #0,1 node-index
k1 = kk*npar #0,6 the starting task-index for node1 and node2
k2 = (kk+1)*npar #6,12 the ending task-index for node1 and node2
print("-----node line -----")
os.system(f"sbatch ./submit_python_mpi4py.sh {kk+1} {k1} {k2}") #
# %%
В приведенном выше примере просто показан пример, в котором mpi4py можно использовать для выполнения параллельных операций на нескольких узлах и нескольких ядрах. В приведенном выше примере нет зависимостей между задачами. Но после завершения цикла for обычно происходит операция concat или что-то в этом роде, и необходимо собрать результаты каждой операции ядра. mpi4py также поддерживает передачу данных между различными задачами. Более подробную информацию можно найти в Интернете.