2015-10-08 3 views
0

Я играл с multiprocessing.Pool и пытался понять, как работает аргумент initializer. Из того, что я понимаю, функция инициализатора вызывается для каждого процесса, поэтому я предположил, что аргументы к ней (т. Е. initargs) должны быть протравлены через границы процесса. Я знаю, что метод пула map также использует травление для своих аргументов, поэтому я предположил, что все, что работает как аргумент для инициализатора, также должно работать как аргумент для сопоставления.многопроцессорный инициализатор и травление

Однако, когда я запускаю следующий фрагмент кода, initialize вызывается просто отлично, но тогда map выдает исключение из-за невозможности разборки модуля. (Нет ничего особенного в том, чтобы использовать текущий модуль в качестве аргумента, это был только первый непродуманный объект, который приходил на ум.) Кто-нибудь знает, что может быть за этим различием?

from __future__ import print_function 
import multiprocessing 
import sys 


def get_pid(): 
    return multiprocessing.current_process().pid 


def initialize(module): 
    print('Got module {} in PID {}'.format(module, get_pid())) 


def worker(module): 
    print('Got module {} in PID {}'.format(module, get_pid())) 


current_module = sys.modules[__name__] 
work = [current_module] 

print('Main process has PID {}'.format(get_pid())) 
pool = multiprocessing.Pool(None, initialize, work) 
pool.map(worker, work) 

ответ

1

Initialize не требует протравливания, но map вызов делает. Возможно, это прольет некоторый свет ... (здесь я использую multiprocess вместо multiprocessing, чтобы дать лучшее травление и интерактивность).

>>> from __future__ import print_function 
>>> import multiprocess as multiprocessing 
>>> import sys 
>>> 
>>> def get_pid(): 
...  return multiprocessing.current_process().pid 
... 
>>> 
>>> def initialize(module): 
...  print('Got module {} in PID {}'.format(module, get_pid())) 
... 
>>> 
>>> def worker(module): 
...  print('Got module {} in PID {}'.format(module, get_pid())) 
... 
>>> 
>>> current_module = sys.modules[__name__] 
>>> work = [current_module] 
>>> 
>>> print('Main process has PID {}'.format(get_pid())) 
Main process has PID 34866 
>>> pool = multiprocessing.dummy.Pool(None, initialize, work) 
Got module <module '__main__' (built-in)> in PID 34866 
Got module <module '__main__' (built-in)> in PID 34866 
Got module <module '__main__' (built-in)> in PID 34866 
Got module <module '__main__' (built-in)> in PID 34866 
Got module <module '__main__' (built-in)> in PID 34866 
Got module <module '__main__' (built-in)> in PID 34866 
Got module <module '__main__' (built-in)> in PID 34866 
Got module <module '__main__' (built-in)> in PID 34866 
>>> pool.map(worker, work) 
Got module <module '__main__' (built-in)> in PID 34866 
[None] 

Прохладный. Нарезание резьбы pool работает ... (потому что не нужно ничего расчётывать). Как насчет того, когда мы отправляем как worker, так и work с использованием сериализации?

>>> pool = multiprocessing.Pool(None, initialize, work) 
Got module <module '__main__' (built-in)> in PID 34875 
Got module <module '__main__' (built-in)> in PID 34876 
Got module <module '__main__' (built-in)> in PID 34877 
Got module <module '__main__' (built-in)> in PID 34878 
Got module <module '__main__' (built-in)> in PID 34879 
Got module <module '__main__' (built-in)> in PID 34880 
Got module <module '__main__' (built-in)> in PID 34881 
Got module <module '__main__' (built-in)> in PID 34882 
>>> pool.map(worker, work) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/Users/mmckerns/lib/python2.7/site-packages/multiprocess-0.70.4.dev0-py2.7-macosx-10.8-x86_64.egg/multiprocess/pool.py", line 251, in map 
    return self.map_async(func, iterable, chunksize).get() 
    File "/Users/mmckerns/lib/python2.7/site-packages/multiprocess-0.70.4.dev0-py2.7-macosx-10.8-x86_64.egg/multiprocess/pool.py", line 567, in get 
    raise self._value 
NotImplementedError: pool objects cannot be passed between processes or pickled 
>>> 

Итак, давайте посмотрим на травление work:

>>> import pickle 
>>> import sys    
>>> pickle.dumps(sys.modules[__name__]) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1374, in dumps 
    Pickler(file, protocol).dump(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 306, in save 
    rv = reduce(self.proto) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy_reg.py", line 70, in _reduce_ex 
    raise TypeError, "can't pickle %s objects" % base.__name__ 
TypeError: can't pickle module objects 
>>> 

Таким образом, вы не можете мариновать модуль ... хорошо, мы можем сделать лучше, используя dill?

>>> import dill 
>>> dill.detect.trace(True) 
>>> dill.pickles(work) 
M1: <module '__main__' (built-in)> 
F2: <function _import_module at 0x10c017cf8> 
# F2 
D2: <dict object at 0x10d9a8168> 
M2: <module 'dill' from '/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.5.dev0-py2.7.egg/dill/__init__.pyc'> 
# M2 
F1: <function worker at 0x10c07fed8> 
F2: <function _create_function at 0x10c017488> 
# F2 
Co: <code object worker at 0x10b053cb0, file "<stdin>", line 1> 
F2: <function _unmarshal at 0x10c017320> 
# F2 
# Co 
D1: <dict object at 0x10af68168> 
# D1 
D2: <dict object at 0x10c0e4a28> 
# D2 
# F1 
M2: <module 'sys' (built-in)> 
# M2 
F1: <function initialize at 0x10c07fe60> 
Co: <code object initialize at 0x10b241f30, file "<stdin>", line 1> 
# Co 
D1: <dict object at 0x10af68168> 
# D1 
D2: <dict object at 0x10c0ea398> 
# D2 
# F1 
M2: <module 'pathos' from '/Users/mmckerns/lib/python2.7/site-packages/pathos-0.2a1.dev0-py2.7.egg/pathos/__init__.pyc'> 
# M2 
C2: __future__._Feature 
# C2 
D2: <dict object at 0x10b05b7f8> 
# D2 
M2: <module 'multiprocess' from '/Users/mmckerns/lib/python2.7/site-packages/multiprocess-0.70.4.dev0-py2.7-macosx-10.8-x86_64.egg/multiprocess/__init__.pyc'> 
# M2 
T4: <class 'pathos.threading.ThreadPool'> 
# T4 
D2: <dict object at 0x10c0ea5c8> 
# D2 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.5.dev0-py2.7.egg/dill/dill.py", line 1209, in pickles 
    pik = copy(obj, **kwds) 
    File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.5.dev0-py2.7.egg/dill/dill.py", line 161, in copy 
    return loads(dumps(obj, *args, **kwds)) 
    File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.5.dev0-py2.7.egg/dill/dill.py", line 197, in dumps 
    dump(obj, file, protocol, byref, fmode, recurse)#, strictio) 
    File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.5.dev0-py2.7.egg/dill/dill.py", line 190, in dump 
    pik.dump(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 600, in save_list 
    self._batch_appends(iter(obj)) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 636, in _batch_appends 
    save(tmp[0]) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.5.dev0-py2.7.egg/dill/dill.py", line 1116, in save_module 
    state=_main_dict) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 419, in save_reduce 
    save(state) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.5.dev0-py2.7.egg/dill/dill.py", line 768, in save_module_dict 
    StockPickler.save_dict(pickler, obj) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 649, in save_dict 
    self._batch_setitems(obj.iteritems()) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 681, in _batch_setitems 
    save(v) 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 306, in save 
    rv = reduce(self.proto) 
    File "/Users/mmckerns/lib/python2.7/site-packages/multiprocess-0.70.4.dev0-py2.7-macosx-10.8-x86_64.egg/multiprocess/pool.py", line 452, in __reduce__ 
    'pool objects cannot be passed between processes or pickled' 
NotImplementedError: pool objects cannot be passed between processes or pickled 
>>> 

Ответ да - модуль начинает маринад, однако, не удается из-за содержания в модуле ... так это выглядит, как он работает за все в __main__ кроме случаев, когда есть экземпляр pool в __main__ - тогда это не удастся.

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

>>> multiprocessing.Pool(None, initialize, work).map(worker, work) 
Got module <module '__main__' (built-in)> in PID 34922 
Got module <module '__main__' (built-in)> in PID 34923 
Got module <module '__main__' (built-in)> in PID 34924 
Got module <module '__main__' (built-in)> in PID 34925 
Got module <module '__main__' (built-in)> in PID 34926 
Got module <module '__main__' (built-in)> in PID 34927 
Got module <module '__main__' (built-in)> in PID 34928 
Got module <module '__main__' (built-in)> in PID 34929 
Got module <module '__main__' (built-in)> in PID 34922 
[None] 
>>> 

Вот с помощью multiprocess, так как он использует dill под одеялом. pickle все равно не будет рассортироваться, потому что pickle не может сериализовать модуль. Сериализация необходима, так как объект должен быть отправлен в другой экземпляр python для другого процесса.

+0

Благодарим вас за подробный ответ и за то, что вы познакомили меня с модулем «multiprocess» :) Не нужно ли разбирать аргумент 'initializer', потому что он может напрямую обращаться к исходной памяти (так как все процессы будут генерироваться через 'fork')? – Shoaib

+0

Просто подтвердил это, установив метод [start method] (https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods) как 'spawn', который действительно требует аргументов функция инициализатора должна быть разборчивой. Еще раз спасибо! – Shoaib

+0

абсолютно правильный –

Смежные вопросы