Я пытаюсь выполнить 100 моделей на моей 8-процессорной 64-разрядной машине Windows 7. Я бы хотел запустить 7 экземпляров модели одновременно, чтобы уменьшить общее время работы (около 9,5 минут на модельный пробег). Я просмотрел несколько потоков, относящихся к модулю многопроцессорности Python, но я все еще что-то пропустил.
Использование модуля многопроцессорности
Как создать параллельные дочерние процессы в многопроцессорной системе?
Многопроцессорная очередь Python
Мой процесс:
У меня есть 100 различных наборов параметров, которые я бы хотел запустить через SEAWAT/MODFLOW, чтобы сравнить результаты. Я предварительно создал входные файлы модели для каждого запуска модели и сохранил их в своих собственных каталогах. То, что я хотел бы иметь, это иметь 7 моделей, работающих одновременно, до тех пор, пока все реализации не будут завершены. Не должно быть связи между процессами или отображением результатов. До сих пор я смог последовательно генерировать модели:
import os,subprocess
import multiprocessing as mp
ws = r'D:\Data\Users\jbellino\Project\stJohnsDeepening\model\xsec_a'
files = []
for f in os.listdir(ws + r'\fieldgen\reals'):
if f.endswith('.npy'):
files.append(f)
## def work(cmd):
## return subprocess.call(cmd, shell=False)
def run(f,def_param=ws):
real = f.split('_')[2].split('.')[0]
print 'Realization %s' % real
mf2k = r'c:\modflow\mf2k.1_19\bin\mf2k.exe '
mf2k5 = r'c:\modflow\MF2005_1_8\bin\mf2005.exe '
seawatV4 = r'c:\modflow\swt_v4_00_04\exe\swt_v4.exe '
seawatV4x64 = r'c:\modflow\swt_v4_00_04\exe\swt_v4x64.exe '
exe = seawatV4x64
swt_nam = ws + r'\reals\real%s\ss\ss.nam_swt' % real
os.system( exe + swt_nam )
if __name__ == '__main__':
p = mp.Pool(processes=mp.cpu_count()-1) #-leave 1 processor available for system and other processes
tasks = range(len(files))
results = []
for f in files:
r = p.map_async(run(f), tasks, callback=results.append)
Я изменил if __name__ == 'main':
на следующее, надеясь, что он исправит недостаток parallelism, который, как мне кажется, передается на script выше for loop
. Тем не менее, модель не может работать даже без ошибки Python:
if __name__ == '__main__':
p = mp.Pool(processes=mp.cpu_count()-1) #-leave 1 processor available for system and other processes
p.map_async(run,((files[f],) for f in range(len(files))))
Любая помощь приветствуется!
РЕДАКТИРОВАТЬ 3/26/2012 13:31 EST
Использование метода "Ручной пул" в @J.F. Ответ Себастьяна ниже. Я получаю параллельное выполнение моего внешнего .exe. Реализация модели вызывается партиями по 8 за раз, но она не дожидается завершения этих 8 прогонов до вызова следующей партии и т.д.:
from __future__ import print_function
import os,subprocess,sys
import multiprocessing as mp
from Queue import Queue
from threading import Thread
def run(f,ws):
real = f.split('_')[-1].split('.')[0]
print('Realization %s' % real)
seawatV4x64 = r'c:\modflow\swt_v4_00_04\exe\swt_v4x64.exe '
swt_nam = ws + r'\reals\real%s\ss\ss.nam_swt' % real
subprocess.check_call([seawatV4x64, swt_nam])
def worker(queue):
"""Process files from the queue."""
for args in iter(queue.get, None):
try:
run(*args)
except Exception as e: # catch exceptions to avoid exiting the
# thread prematurely
print('%r failed: %s' % (args, e,), file=sys.stderr)
def main():
# populate files
ws = r'D:\Data\Users\jbellino\Project\stJohnsDeepening\model\xsec_a'
wdir = os.path.join(ws, r'fieldgen\reals')
q = Queue()
for f in os.listdir(wdir):
if f.endswith('.npy'):
q.put_nowait((os.path.join(wdir, f), ws))
# start threads
threads = [Thread(target=worker, args=(q,)) for _ in range(8)]
for t in threads:
t.daemon = True # threads die if the program dies
t.start()
for _ in threads: q.put_nowait(None) # signal no more files
for t in threads: t.join() # wait for completion
if __name__ == '__main__':
mp.freeze_support() # optional if the program is not frozen
main()
Отсутствует трассировка ошибок. Функция run()
выполняет свою обязанность при вызове одного файла реализации модели, как с несколькими файлами. Единственное различие заключается в том, что с несколькими файлами он называется len(files)
раз, хотя каждый из экземпляров немедленно закрывается, и только один запуск модели разрешен, и в это время script выходит изящно (код выхода 0).
Добавление некоторых операторов печати в main()
показывает некоторую информацию об активных подсчетах потоков, а также о состоянии потока (обратите внимание, что это тест только для 8 файлов реализации, чтобы сделать снимок экрана более управляемым, теоретически все 8 файлов должны запускаться одновременно, однако поведение продолжается там, где они появляются и сразу умирают, кроме одного):
def main():
# populate files
ws = r'D:\Data\Users\jbellino\Project\stJohnsDeepening\model\xsec_a'
wdir = os.path.join(ws, r'fieldgen\test')
q = Queue()
for f in os.listdir(wdir):
if f.endswith('.npy'):
q.put_nowait((os.path.join(wdir, f), ws))
# start threads
threads = [Thread(target=worker, args=(q,)) for _ in range(mp.cpu_count())]
for t in threads:
t.daemon = True # threads die if the program dies
t.start()
print('Active Count a',threading.activeCount())
for _ in threads:
print(_)
q.put_nowait(None) # signal no more files
for t in threads:
print(t)
t.join() # wait for completion
print('Active Count b',threading.activeCount())
** Строка, которая читает "D:\\Data\\Users...
", - это информация об ошибке, которая была сброшена, когда я вручную остановил работу модели до ее завершения. Как только я остановлю работу модели, появятся остальные строки состояния потока, и script завершает работу.
РЕДАКТИРОВАТЬ 3/26/2012 16:24 EST
SEAWAT разрешает одновременное выполнение, как я делал это в прошлом, запускать экземпляры вручную с помощью iPython и запускать из каждой папки файла модели. На этот раз я запускаю все прогоны моделей из одного места, а именно в каталог, где находится мой script. Похоже, что виновник может быть в том, как SEAWAT экономит часть продукции. Когда SEAWAT запущен, он немедленно создает файлы, относящиеся к прогону модели. Один из этих файлов не сохраняется в каталоге, в котором находится реализация модели, но в верхнем каталоге, где находится script. Это предотвращает сохранение любых последующих потоков одним и тем же именем в одном и том же месте (которое все они хотят сделать, поскольку эти имена файлов являются универсальными и неспецифическими для каждой реализации). Окна SEAWAT не оставались открытыми достаточно долго, чтобы я мог читать или даже видеть, что было сообщение об ошибке, я только это понял, когда вернулся, и попытался запустить код с помощью iPython, который непосредственно отображает распечатку из SEAWAT вместо того, чтобы открывать новое окно для запуска программы.
Я принимаю @J.F. Себастьян отвечает, так как вполне вероятно, что, как только я разрешу эту проблему с исполнением модели, предоставленный им код потоковой передачи получит меня там, где мне нужно.
ЗАКЛЮЧИТЕЛЬНЫЙ КОД
Добавлен аргумент cwd в subprocess.check_call для запуска каждого экземпляра SEAWAT в его собственном каталоге. Очень важно.
from __future__ import print_function
import os,subprocess,sys
import multiprocessing as mp
from Queue import Queue
from threading import Thread
import threading
def run(f,ws):
real = f.split('_')[-1].split('.')[0]
print('Realization %s' % real)
seawatV4x64 = r'c:\modflow\swt_v4_00_04\exe\swt_v4x64.exe '
cwd = ws + r'\reals\real%s\ss' % real
swt_nam = ws + r'\reals\real%s\ss\ss.nam_swt' % real
subprocess.check_call([seawatV4x64, swt_nam],cwd=cwd)
def worker(queue):
"""Process files from the queue."""
for args in iter(queue.get, None):
try:
run(*args)
except Exception as e: # catch exceptions to avoid exiting the
# thread prematurely
print('%r failed: %s' % (args, e,), file=sys.stderr)
def main():
# populate files
ws = r'D:\Data\Users\jbellino\Project\stJohnsDeepening\model\xsec_a'
wdir = os.path.join(ws, r'fieldgen\reals')
q = Queue()
for f in os.listdir(wdir):
if f.endswith('.npy'):
q.put_nowait((os.path.join(wdir, f), ws))
# start threads
threads = [Thread(target=worker, args=(q,)) for _ in range(mp.cpu_count()-1)]
for t in threads:
t.daemon = True # threads die if the program dies
t.start()
for _ in threads: q.put_nowait(None) # signal no more files
for t in threads: t.join() # wait for completion
if __name__ == '__main__':
mp.freeze_support() # optional if the program is not frozen
main()