Использование многопроцессорного модуля

#python #multiprocessing

#python #многопроцессорная обработка

Вопрос:

Я пытаюсь использовать многопроцессорный модуль в python 2.6, но, видимо, есть что-то, чего я не понимаю. Я бы ожидал, что приведенный ниже класс сложит числа, отправленные ему с помощью add(), и вернет сумму в методе get_result() . Приведенный ниже код выводит «0», я бы хотел, чтобы он выводил «2». Что я пропустил?

 import multiprocessing

class AdderProcess(multiprocessing.Process):

    def __init__(self):
        multiprocessing.Process.__init__(self)
        self.sum = 0
        self.queue = multiprocessing.JoinableQueue(5)
        self.daemon = True
        self.start()

    def run(self):
        while True:
            number = self.queue.get()
            self.sum  = number
            self.queue.task_done()

    def add(self, number):
        self.queue.put(number)

    def get_result(self):
        self.queue.join()
        return self.sum


p = AdderProcess()
p.add(1)
p.add(1)
print p.get_result()
  

PS. Эта проблема решена.Спасибо за ответы! Просто чтобы облегчить читателям, вот полная рабочая версия:

 import multiprocessing

class AdderProcess(multiprocessing.Process):

    def __init__(self):
        multiprocessing.Process.__init__(self)
        self.sum = multiprocessing.Value('d', 0.0)
        self.queue = multiprocessing.JoinableQueue(5)
        self.daemon = True
        self.start()

    def run(self):
        while True:
            number = self.queue.get()
            self.sum.value  = number
            self.queue.task_done()

    def add(self, number):
        self.queue.put(number)

    def get_result(self):
        self.queue.join()
        return self.sum.value

p = AdderProcess()
p.add(1)
p.add(1)
print p.get_result()
  

Ответ №1:

Измените self.sum = 0 на self.sum = multiprocessing.Value('d', 0.0) и используйте self.sum.value для доступа или изменения значения.

 class AdderProcess(multiprocessing.Process):    
    def __init__(self):
        ...
        self.sum = multiprocessing.Value('d', 0.0) 
        ...
    def run(self):
        while True:
            number = self.queue.get()
            self.sum.value  = number    # <-- use self.sum.value
            self.queue.task_done()
    def get_result(self):
        self.queue.join()
        return self.sum.value           # <-- use self.sum.value
  

Проблема заключается в следующем: как только вы вызываете self.start() __init__ , основной процесс разветвляет дочерний процесс. Все значения копируются. Теперь есть две версии p . В основном процессе p.sum равно 0. В дочернем процессе run вызывается метод, p.sum который увеличивается до 2. Но когда вызывается основной процесс p.get_result() , его версия p по-прежнему p.sum равна 0.
Таким образом, выводится 0.

Когда вы хотите поделиться значением с плавающей запятой между процессами, вам необходимо использовать механизм совместного использования, например mp.Value .

Дополнительные параметры совместного использования значений см. в разделе «Совместное использование состояния между процессами«.

Комментарии:

1. Предполагая, что вы имеете в виду, что я должен заменить свой инициализатор вашим кодом, этот код вызывает исключение TypeError при выполнении. Это сработало для вас? Не могли бы вы подробнее рассказать о том, что вы здесь делаете?

2. Извините, я запустил код, я просто забыл включить все свои изменения. Вам также необходимо изменить self.sum self.sum.value , чтобы получить доступ или изменить значение.

3. Хорошо, я думаю, что теперь я понял. Не существует магии RPC, которая заставляет вызовы методов переходить к другому процессу, единственная общая информация — это та, которая явно используется для типов данных, предоставленных для этой цели. Думаю, это имеет смысл. Спасибо!

Ответ №2:

self.sum равно 2… в этом процессе:

 def run(self):
    while True:
        number = self.queue.get()
        print "got %s from queue" % number
        print "Before adding - self.sum = %d" % self.sum
        self.sum  = number
        print "After adding - self.sum = %d" % self.sum
        self.queue.task_done()

[ 13:56 jon@host ~ ]$ ./mp.py
got 1 from queue
Before adding - self.sum = 0
After adding - self.sum = 1
got 1 from queue
Before adding - self.sum = 1
After adding - self.sum = 2
  

Смотрите раздел многопроцессорная обработка 16.3.1.4. — Совместное использование состояния между процессами о том, как добиться self.sum одинакового состояния в разных процессах.