Python Multiprocessing - просто не понимаю - PullRequest
6 голосов
/ 15 июня 2011

Я потратил некоторое время, пытаясь понять многопроцессорность, хотя ее тонкости уклоняются от моего неподготовленного ума. Мне удалось заставить пул возвращать простое целое число, но если функция не просто возвращает результат, как все примеры, которые я могу найти (даже в документации , это какой-то неясный пример Я не совсем понимаю.

Вот пример, который я пытаюсь заставить работать. НО, я не могу заставить его работать как положено, и я уверен, что есть простая причина, почему. Мне может понадобиться использовать очередь, общую память или менеджера, но столько раз, сколько я читаю документацию, я не могу понять, что это на самом деле означает и что делает. Все, что я смог понять до сих пор, это функция пула.

Кроме того, я использую класс, так как мне нужно избегать использования глобальных переменных, как в ответе на этот вопрос .

import random

class thisClass:
    def __init__(self):
        self.i = 0

def countSixes(myClassObject):
    newNum = random.randrange(0,10)
    #print(newNum) #this proves the function is being run if enabled
    if newNum == 6:
        myClassObject.i += 1

if __name__ == '__main__':
    import multiprocessing
    pool = multiprocessing.Pool(1) #use one core for now

    counter = thisClass()

    myList = []
    [myList.append(x) for x in range(1000)]

    #it must be (args,) instead of just i, apparently
    async_results = [pool.apply_async(countSixes, (counter,)) for i in myList]

    for x in async_results:
        x.get(timeout=1)

    print(counter.i)

Может ли кто-нибудь объяснить, что нужно сделать, чтобы я наконец понял, чего мне не хватает и что это делает?

1 Ответ

12 голосов
/ 15 июня 2011

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

Прямо сейчас вы отправляете объекты в свой пул для изменения и ничего не возвращаете из countSixes. Это не будет работать с многопроцессорной обработкой, потому что для обхода GIL многопроцессорная обработка создает копию из counter и отправляет ее новому интерпретатору, Поэтому, когда вы увеличиваете i, вы фактически увеличиваете копию из i, а затем, поскольку вы ничего не возвращаете, вы отбрасываете ее!

Чтобы сделать что-то полезное, вы должны вернуть что-то из countSixes. Вот упрощенная версия вашего кода, которая делает что-то похожее на то, что вы хотите. Я оставил аргумент, чтобы показать, что вы должны делать, но на самом деле это можно сделать с помощью функции с нулевым аргументом.

import random

def countSixes(start):
    newNum = random.randrange(0,10)
    if newNum == 6:
        return start + 1
    else:
        return start

if __name__ == '__main__':
    import multiprocessing
    pool = multiprocessing.Pool(1) #use one core for now

    start = 0
    async_results = [pool.apply_async(countSixes, (start,)) for i in range(1000)]

    print(sum(r.get() for r in async_results))
...