2015-02-01 14 views
7

Ten kod wieloprocesowy działa zgodnie z oczekiwaniami. Tworzy 4 procesy Pythona i używa ich do drukowania liczb od 0 do 39, z opóźnieniem po każdym wydruku.Blokady wieloprocesorowe Python

import multiprocessing 
import time 

def job(num): 
    print num 
    time.sleep(1) 

pool = multiprocessing.Pool(4) 

lst = range(40) 
for i in lst: 
    pool.apply_async(job, [i]) 

pool.close() 
pool.join() 

Jednak gdy próbuję użyć multiprocessing.Lock aby zapobiec wielu procesów od drukowania na standardowe wyjście, program po prostu wychodzi natychmiast bez wyjścia.

import multiprocessing 
import time 

def job(lock, num): 
    lock.acquire() 
    print num 
    lock.release() 
    time.sleep(1) 

pool = multiprocessing.Pool(4) 
l = multiprocessing.Lock() 

lst = range(40) 
for i in lst: 
    pool.apply_async(job, [l, i]) 

pool.close() 
pool.join() 

Dlaczego wprowadzenie wieloprocesowości. Blokada powoduje, że ten kod nie działa?

Aktualizacja: Działa, gdy blokada jest zadeklarowana globalnie (gdzie wykonałem kilka nieokreślonych testów, aby sprawdzić, czy blokada działa), w przeciwieństwie do kodu powyżej, który przekazuje blokadę jako argument (dokumentacja wieloprocesowa Pythona pokazuje blokady przekazywane jako argumenty). Poniższy kod ma zadeklarowaną globalnie blokadę, w przeciwieństwie do podania jako argument w powyższym kodzie.

import multiprocessing 
import time 

l = multiprocessing.Lock() 

def job(num): 
    l.acquire() 
    print num 
    l.release() 
    time.sleep(1) 

pool = multiprocessing.Pool(4) 

lst = range(40) 
for i in lst: 
    pool.apply_async(job, [i]) 

pool.close() 
pool.join() 

Odpowiedz

6

Jeśli zmieniają pool.apply_async do pool.apply, można uzyskać ten wyjątek:

Traceback (most recent call last): 
    File "p.py", line 15, in <module> 
    pool.apply(job, [l, i]) 
    File "/usr/lib/python2.7/multiprocessing/pool.py", line 244, in apply 
    return self.apply_async(func, args, kwds).get() 
    File "/usr/lib/python2.7/multiprocessing/pool.py", line 558, in get 
    raise self._value 
RuntimeError: Lock objects should only be shared between processes through inheritance 

pool.apply_async to po prostu ukrywa. Nienawidzę tego mówić, ale używanie zmiennej globalnej jest prawdopodobnie najprostszym sposobem na twój przykład. Miejmy nadzieję, że velociraptors Cię nie dostanie.

+0

Dzięki! Używanie polecenia apply w przeciwieństwie do apply_async wydaje się przydatnym sposobem debugowania tych problemów. –

+0

Tak, wydaje się nieco głupie, że 'apply_async' nawet nie wyświetla ostrzeżenia. – matsjoyce

+0

Zgadzam się, ale jako obejście można użyć w Pythonie 3 error_callback z apply_async. Obejście dla Python 2 -> http://stackoverflow.com/questions/27986885/error-callback-in-multiprocessing-pool-apply-async-in-python-2 – TitanFighter

3

Myślę, że powodem jest to, że basen wieloprocesorowe wykorzystuje pickle do przesyłania obiektów między procesami. Jednak Lock nie mogą być kiszone:

>>> import multiprocessing 
>>> import pickle 
>>> lock = multiprocessing.Lock() 
>>> lp = pickle.dumps(lock) 
Traceback (most recent call last): 
    File "<pyshell#3>", line 1, in <module> 
    lp = pickle.dumps(lock) 
... 
RuntimeError: Lock objects should only be shared between processes through inheritance 
>>> 

Patrz „Picklability” i „Lepiej dziedziczyć niż zalewie/unpickle” odcinki https://docs.python.org/2/library/multiprocessing.html#all-platforms

Powiązane problemy