5

Powyżej znajduje się pełna prosty przykład działaOptimzing multiprocessing.Pool z drogich inicjalizacji

import multiprocessing as mp 
import time 
import random 


class Foo: 
    def __init__(self): 
     # some expensive set up function in the real code 
     self.x = 2 
     print('initializing') 

    def run(self, y): 
     time.sleep(random.random()/10.) 
     return self.x + y 


def f(y): 
    foo = Foo() 
    return foo.run(y) 


def main(): 
    pool = mp.Pool(4) 
    for result in pool.map(f, range(10)): 
     print(result) 
    pool.close() 
    pool.join() 


if __name__ == '__main__': 
    main() 

Jak mogę go zmodyfikować tak Foo jest inicjowana tylko raz przez każdego pracownika, nie każde zadanie? Zasadniczo chcę init nazywa się 4 razy, a nie 10. Używam Python 3.5

+0

Czy byłoby dobrze, gdyby klasa została zainicjalizowana tylko raz, a następnie skopiowana do każdego pracownika? –

+0

@BrendanAbel Tak myślę. Oznacza to, że przedmiot musi być do ogarnięcia? Obiekt nie jest zmutowany po inicjalizacji, więc nie wiem, dlaczego kopiowanie byłoby złe. – user2133814

+0

Wieloprocesorowość to * nie * to samo co wielowątkowość. Mają bardzo różne cechy. – jpmc26

Odpowiedz

6

Zamierzony sposób na radzenie sobie z rzeczy, jak to odbywa się za pomocą opcjonalnych initializer i initargs argumentów do konstruktora Pool(). Istnieją one dokładnie po to, aby dać ci sposób na zrobienie rzeczy dokładnie raz, gdy tworzony jest proces roboczy. Tak więc, na przykład, dodać:

def init(): 
    global foo 
    foo = Foo() 

i zmienić tworzenie Pool do:

pool = mp.Pool(4, initializer=init) 

Jeśli potrzebne do przekazywania argumentów do funkcji każdego procesu inicjalizacji, to by też dodać odpowiedni initargs=... argument.

Uwaga: Oczywiście należy również usunąć wiersz

foo = Foo() 

od f(), tak że funkcja wykorzystuje globalny foo stworzony przez init().

+0

Czy możesz wyjaśnić globalne słowo kluczowe w tym kontekście. Widziałem inicjatora w dokumentach, ale nie myślałem/nie wiem o "globalnym", więc nie widziałem, jak to zrobić. Dzięki – user2133814

+0

Zobacz już teraz moją edycję: musisz również _use_ "foo" stworzone przez funkcję inicjalizacji. Funkcja inicjalizacyjna działa raz i kończy się, więc każda jej zmiana musi być widoczna w zasięgu globalnym, aby inne funkcje (takie jak wywoływane przez 'map()') mogły przynieść korzyści. –

+1

Nie. Nic nie jest współdzielone pomiędzy procesami. 'global' jest w Pythonie od pierwszego dnia, wiele lat przed" multiprocessing "był nawet pomysłem na moduł. 'global' nie ma nic wspólnego z procesami (lub wątkami). W kontekście jest to po prostu polecenie 'init()' do wiązania 'foo' w globalnym zasięgu modułu zamiast w (domyślnym) lokalnym zasięgu' init'. W trybie wieloprocesowym każdy proces ma własną, odrębną globalną przestrzeń nazw modułu. –

2

najbardziej oczywistą, leniwy obciążenia

_foo = None 
def f(y): 
    global _foo 
    if not _foo: 
     _foo = Foo() 
    return _foo.run(y) 
+1

Dlaczego masz globalne '_foo', którego nigdy nie odwołujesz? – Bakuriu

Powiązane problemy