2016-06-20 1 views
0

рассмотрят следующие объекты:Изменение свойств объекта в Python мультипроцессорных

class Item(object): 
    def __init__(self): 
     self.c = 0 
    def increase(self): 
     S.increase(self) 

class S(object): 
    @staticmethod 
    def increase(item): 
     item.c += 1 

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

from multiprocessing import Process 
l= [Item() for i in range(5)] 
for i in l: 
    Process(target=i.increase).start() 

В результате это не то, что я ожидал:

[i.c for i in l] 
[0, 0, 0, 0, 0] 

Где я буду неправильно?

+0

Это не имеет никакого отношения к использованию статических методов, а скорее к тому, как работает многопроцессорный модуль. Когда вы начинаете новый «Процесс», он получает * копию * каждого объекта «i». Например, http://stackoverflow.com/questions/3044580/multiprocessing-vs-threading-python?rq=1. Чтобы получить обратно мутированный объект, вы должны либо отправить его обратно из процесса, либо поместить его в общую область: https://docs.python.org/2/library/multiprocessing.html#sharing-state-between-processes – torek

+0

Это, кажется, проблема, если вы отправляете ее в качестве ответа, я могу дать вам знак! Большое спасибо! – Kai

ответ

1

Вы ждете вашего мутатор, статический метод increase в классе S (вызывается из нестатической increase в классе item) для настройки каждого i.c поля, и это делает. Проблема заключается не в статическом методе, а в внутреннем дизайне multiprocessing.

Пакет multiprocessing работает путем запуска нескольких отдельных экземпляров Python. В Unix-подобных системах он использует fork, что делает это проще; на Windows-подобных системах он порождает новые копии. В любом случае это накладывает все несколько нечетные ограничения, описанные в документации Python: v2 и v3. (NB: остальные ссылки ниже относятся к документации Python2, так как это была страница, которую я все еще имел. Ограничения почти одинаковы для Python2 и Python3.)

В этом конкретном случае каждый вызов Process делает копию объекта i и отправляет эту копию в новый процесс. Процесс изменяет копию, которая не влияет на оригинал.

Чтобы исправить это, вы можете либо отправить измененные объекты обратно, например, через Queue() or Pipe() instance, либо поместить объекты в shared memory. Технология отправки назад проще и проще программировать и автоматически выполняет большую часть необходимой синхронизации (но см. Предостережение о том, чтобы собрать все результаты, прежде чем использовать экземпляр процесса join, даже неявно).