Я должен заранее извиниться, потому что этот вопрос довольно общий и может быть недостаточно ясен. Возникает вопрос: как бы вы запускали параллельно функцию Python, которая сама использует пул процессов для некоторых подзадач и выполняет множество тяжелых операций ввода-вывода? Это вообще актуальная задача?
Я постараюсь предоставить дополнительную информацию. У меня есть процедура, скажем test_reduce()
, которую мне нужно запустить параллельно. Я попробовал несколько способов сделать это (см. ниже), и мне, похоже, не хватает знаний, чтобы понять, почему все они терпят неудачу.
Эта test_reduce()
процедура делает много вещей. Некоторые из них более актуальны для вопроса, чем другие (и я перечисляю их ниже):
- Он использует модуль
multiprocessing
(sic!), а именно экземплярpool.Pool
, - Он использует соединение MongoDB,
- Он сильно зависит от
numpy
иscikit-learn
libs, - Он использует обратные вызовы и лямбды,
- Он использует библиотеку
dill
для обработки некоторых вещей.
Сначала я попытался использовать multiprocessing.dummy.Pool
(который, кажется, является пулом потоков). Я не знаю, что особенного в этом пуле и почему он, э-э, "фиктивный"; все это работало, и я получил свои результаты. Проблема заключается в загрузке процессора. Для распараллеленных секций test_reduce()
было 100% для всех ядер; для синхронных участков большую часть времени он составлял около 40-50%. Я не могу сказать, что было какое-то увеличение общей скорости для такого типа "параллельного" выполнения.
Затем я попытался использовать multiprocessing.pool.Pool
экземпляр для map
этой процедуры с моими данными. Это не удалось со следующим:
File "/usr/lib/python2.7/multiprocessing/pool.py", line 251, in map
return self.map_async(func, iterable, chunksize).get()
File "/usr/lib/python2.7/multiprocessing/pool.py", line 558, in get
raise self._value
cPickle.PicklingError: Can't pickle <type 'thread.lock'>: attribute lookup thread.lock failed
Я предположил, что виноват cPickle
, и нашел библиотеку pathos
, в которой используется гораздо более продвинутый пиклер dill
. Однако это также терпит неудачу:
File "/local/lib/python2.7/site-packages/dill/dill.py", line 199, in load
obj = pik.load()
File "/usr/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
File "/usr/lib/python2.7/pickle.py", line 1083, in load_newobj
obj = cls.__new__(cls, *args)
TypeError: object.__new__(generator) is not safe, use generator.__new__()
Я совсем не понимаю эту ошибку. У меня нет выходных данных для stdout
из моей процедуры, когда она работает в пуле, поэтому трудно предположить, что происходит. Единственное, что я знаю, это то, что test_reduce()
успешно работает, когда многопроцессорность не используется.
Итак, как бы вы запускали параллельно что-то такое тяжелое и сложное?
QProcess
, который похож на библиотека подпроцессов. Обычно это менее сложно, чем использование нити. - person Mel   schedule 07.07.2015multiprocessing
(в нем широко используется травление). - person oopcode   schedule 07.07.2015dill
иpathos
. Да, можно вложить одну карту в другую. Есть несколько примеров на SO (поиск иерархической параллели).. ноmap(f1, map(f2, x, y))
абсолютно должен работать, если вы не столкнетесь с проблемой сериализации. Похоже, вы пытаетесь замариновать генератор(i for i in x)
, с которымdill
не справляется. - person Mike McKerns   schedule 08.07.2015