2015-11-13 4 views
1

Я предположил, что пакет многопроцессорности использует рассол для отправки вещей между процессами. Однако рассол обращает внимание на методы __getstate__ и __setstate__ объекта. Многопроцессорность, кажется, игнорирует их. Это верно? Я в замешательстве?многопроцессорное игнорирование «__setstate__»

Для репликации, установите докер, и введите в командной строке

$ docker run python:3.4 python -c "import pickle 
import multiprocessing 
import os 

class Tricky: 
    def __init__(self,x): 
     self.data=x 

    def __setstate__(self,d): 
     self.data=10 

    def __getstate__(self): 
     return {} 

def report(ar,q): 
    print('running report in pid %d, hailing from %d'%(os.getpid(),os.getppid())) 
    q.put(ar.data) 

print('module loaded in pid %d, hailing from pid %d'%(os.getpid(),os.getppid())) 
if __name__ == '__main__': 
    print('hello from pid %d'%os.getpid()) 
    ar = Tricky(5) 
    q = multiprocessing.Queue() 
    p = multiprocessing.Process(target=report, args=(ar, q)) 
    p.start() 
    p.join() 
    print(q.get()) 
    print(pickle.loads(pickle.dumps(ar)).data)" 

Вы должны получить что-то вроде

module loaded in pid 1, hailing from pid 0 
hello from pid 1 
running report in pid 5, hailing from 1 
5 
10 

Я бы подумал, что было бы «10» «10», но вместо того, чтобы это «5» «10». Что это могло означать?

(Примечание: код отредактирован соответствует руководящим принципам программирования, как это было предложено user3667217)

ответ

0

Напоминание: когда вы используете мультипроцессирование, вы должны начать процесс в 'if __name__ == '__main__': пункте: (см programming guidelines)

import pickle 
import multiprocessing 

class Tricky: 
    def __init__(self,x): 
     self.data=x 

    def __setstate__(self, d): 
     print('setstate happening') 
     self.data = 10 

    def __getstate__(self): 
     return self.data 
     print('getstate happening') 

def report(ar,q): 
    q.put(ar.data) 

if __name__ == '__main__': 
    ar = Tricky(5) 
    q = multiprocessing.Queue() 
    p = multiprocessing.Process(target=report, args=(ar, q)) 
    print('now starting process') 
    p.start() 
    print('now joining process') 
    p.join() 
    print('now getting results from queue') 
    print(q.get()) 
    print('now getting pickle dumps') 
    print(pickle.loads(pickle.dumps(ar)).data) 

На окнах, я вижу

now starting process 
now joining process 
setstate happening 
now getting results from queue 
10 
now getting pickle dumps 
setstate happening 
10 

На Ubu ntu, я вижу:

now starting process 
now joining process 
now getting results from queue 
5 
now getting pickle dumps 
getstate happening 
setstate happening 
10 

Я полагаю, что это должно ответить на ваш вопрос. multiprocess вызывает метод __setstate__ в Windows, но не в Linux. И в Linux, когда вы звоните pickle.dumps, он сначала звонит __getstate__, затем __setstate__. Интересно посмотреть, как многопроцессорный модуль ведет себя по-разному на разных платформах.

+0

Что-то пошло ужасно неправильно. Какую версию python вы используете? Я скопировал и вставил ваш точный код, запустил его и получил (5,10). –

+0

Вы работаете с окнами, не так ли? Теперь все ясно ... –

+0

Я немного отредактировал свой ответ. Он ведет себя по-разному на разных платформах, и, как вы указали, это команда fork, доступная в системе POSIX. – user3667217

3

Модуль многопроцессорной обработки может запускаться одним из трех способов: икру, вилкой или forkserver. По умолчанию в unix это вилки. Это означает, что нет необходимости собирать все, что уже загружено в баран, в тот момент, когда рождается новый процесс.

Если вам требуется более прямой контроль над тем, как вы хотите, чтобы вилка имела место, вам нужно изменить настройку запуска на икру. Чтобы сделать это, создайте контекст

ctx=multiprocessing.get_context('spawn') 

и заменить все вызовы multiprocessing.foo() с вызовами ctx.foo(). Когда вы это делаете, каждый новый процесс рождается как новый экземпляр python; все, что попадает в него, будет отправлено через рассол вместо прямой memcopy.

+0

Примечание. Кажется, это только Python 3. – MRocklin