2013-03-12 16 views
11

Rozglądałem się po dobrej implementacji prostego wzorca wątku Pythona i naprawdę nie mogę znaleźć niczego, co odpowiada moim potrzebom. Używam Pythona 2.7 i wszystkie moduły, które znalazłem albo nie działają, albo nie obsługują wyjątków w pracownikach prawidłowo. Zastanawiałem się, czy ktoś wie o bibliotece, która mogłaby zaoferować rodzaj funkcjonalności, której szukam. Pomoc bardzo doceniona.Pula wątków w języku Python obsługująca wyjątki

Multiprocessing

Moja pierwsza próba była z wbudowanym modułem multiprocessing, ale ponieważ nie wykorzystuje wątki podprocesów ale zamiast tego napotkasz problem, że obiekty nie mogą być marynowanych. Nie idź tutaj.

from multiprocessing import Pool 

class Sample(object): 
    def compute_fib(self, n): 
     phi = (1 + 5**0.5)/2 
     self.fib = int(round((phi**n - (1-phi)**n)/5**0.5)) 

samples = [Sample() for i in range(8)] 
pool = Pool(processes=8) 
for s in samples: pool.apply_async(s.compute_fib, [20]) 
pool.join() 
for s in samples: print s.fib 

# PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed 

Futures

Więc widzę, że jest z powrotem port niektórych chłodnych jednoczesnych cech Pythona 3.2 here. Wydaje się to idealne i proste w użyciu. Problem polega na tym, że gdy otrzymasz wyjątek w jednym z robotów, otrzymasz tylko typ wyjątku, taki jak "ZeroDivisionError", ale bez śledzenia, a zatem brak wskazania, która linia spowodowała wyjątek. Kod staje się niemożliwy do debugowania. Nie idź.

from concurrent import futures 

class Sample(object): 
    def compute_fib(self, n): 
     phi = (1 + 5**0.5)/2 
     1/0 
     self.fib = int(round((phi**n - (1-phi)**n)/5**0.5)) 

samples = [Sample() for i in range(8)] 
pool = futures.ThreadPoolExecutor(max_workers=8) 
threads = [pool.submit(s.compute_fib, 20) for s in samples] 
futures.wait(threads, return_when=futures.FIRST_EXCEPTION) 
for t in threads: t.result() 
for s in samples: print s.fib 


# futures-2.1.3-py2.7.egg/concurrent/futures/_base.pyc in __get_result(self) 
# 354  def __get_result(self): 
# 355   if self._exception: 
#--> 356    raise self._exception 
# 357   else: 
# 358    return self._result 
# 
# ZeroDivisionError: integer division or modulo by zero 

WorkerPool

znalazłem inne zastosowania tego wzoru here. Tym razem, gdy wystąpi wyjątek, zostanie on wydrukowany, ale mój interpreter interakcyjny ipython pozostanie w stanie zawieszenia i musi zostać zabity z innej powłoki. Nie idź.

import workerpool 

class Sample(object): 
    def compute_fib(self, n): 
     phi = (1 + 5**0.5)/2 
     1/0 
     self.fib = int(round((phi**n - (1-phi)**n)/5**0.5)) 

samples = [Sample() for i in range(8)] 
pool = workerpool.WorkerPool(size=8) 
for s in samples: pool.map(s.compute_fib, [20]) 
pool.wait() 
for s in samples: print s.fib 

# ZeroDivisionError: integer division or modulo by zero 
# ^C^C^C^C^C^C^C^C^D^D 
# $ kill 1783 

puli wątków

Jeszcze Innym realizacja here. Tym razem, gdy wystąpi wyjątek, jest on drukowany do stderr, ale skrypt nie jest przerywany, a zamiast tego kontynuuje wykonywanie, co sprzeciwia się celowi wyjątku i może sprawić, że rzeczy będą niebezpieczne. Nadal nie nadaje się do użytku.

import threadpool 

class Sample(object): 
    def compute_fib(self, n): 
     phi = (1 + 5**0.5)/2 
     1/0 
     self.fib = int(round((phi**n - (1-phi)**n)/5**0.5)) 

samples = [Sample() for i in range(8)] 
pool = threadpool.ThreadPool(8) 
requests = [threadpool.makeRequests(s.compute_fib, [20]) for s in samples] 
requests = [y for x in requests for y in x] 
for r in requests: pool.putRequest(r) 
pool.wait() 
for s in samples: print s.fib 

# ZeroDivisionError: integer division or modulo by zero 
# ZeroDivisionError: integer division or modulo by zero 
# ZeroDivisionError: integer division or modulo by zero 
# ZeroDivisionError: integer division or modulo by zero 
# ZeroDivisionError: integer division or modulo by zero 
# ZeroDivisionError: integer division or modulo by zero 
# ZeroDivisionError: integer division or modulo by zero 
# ZeroDivisionError: integer division or modulo by zero 
#---> 17 for s in samples: print s.fib 
# 
#AttributeError: 'Sample' object has no attribute 'fib' 

- Update -

Wydaje się, że w sprawie biblioteki futures, zachowanie pytona 3 nie jest taka sama jak pyton 2.

futures_exceptions.py:

from concurrent.futures import ThreadPoolExecutor, as_completed 

def div_zero(x): 
    return x/0 

with ThreadPoolExecutor(max_workers=4) as executor: 
    futures = executor.map(div_zero, range(4)) 
    for future in as_completed(futures): print(future) 

Pythonie 2.7.6 Wyjście:

Traceback (most recent call last): 
    File "...futures_exceptions.py", line 12, in <module> 
    for future in as_completed(futures): 
    File "...python2.7/site-packages/concurrent/futures/_base.py", line 198, in as_completed 
    with _AcquireFutures(fs): 
    File "...python2.7/site-packages/concurrent/futures/_base.py", line 147, in __init__ 
    self.futures = sorted(futures, key=id) 
    File "...python2.7/site-packages/concurrent/futures/_base.py", line 549, in map 
    yield future.result() 
    File "...python2.7/site-packages/concurrent/futures/_base.py", line 397, in result 
    return self.__get_result() 
    File "...python2.7/site-packages/concurrent/futures/_base.py", line 356, in __get_result 
    raise self._exception 
ZeroDivisionError: integer division or modulo by zero 

Python 3.3.2 wyjściowe:

Traceback (most recent call last): 
    File "...futures_exceptions.py", line 11, in <module> 
    for future in as_completed(futures): 
    File "...python3.3/concurrent/futures/_base.py", line 193, in as_completed 
    with _AcquireFutures(fs): 
    File "...python3.3/concurrent/futures/_base.py", line 142, in __init__ 
    self.futures = sorted(futures, key=id) 
    File "...python3.3/concurrent/futures/_base.py", line 546, in result_iterator 
    yield future.result() 
    File "...python3.3/concurrent/futures/_base.py", line 392, in result 
    return self.__get_result() 
    File "...python3.3/concurrent/futures/_base.py", line 351, in __get_result 
    raise self._exception 
    File "...python3.3/concurrent/futures/thread.py", line 54, in run 
    result = self.fn(*self.args, **self.kwargs) 
    File "...futures_exceptions.py", line 7, in div_zero 
    return x/0 
ZeroDivisionError: division by zero 
+0

To nie całkowicie rozwiązać problem, ale mam jedną sztuczkę często używaną w debugowanie te problemy jest tymczasowo zastąpić wywołanie 'pool.map' z wezwaniem do wbudowana 'mapa'. –

Odpowiedz

0

proste rozwiązanie: Użyj wszelkimi alternatywne najbardziej Ci odpowiada i zaimplementować własną try-except blok w swoich pracowników. Otocz roota, jeśli musisz.

Nie powiedziałbym, że te biblioteki obsługują wyjątki "niepoprawnie". Mają zachowanie domyślne, jakkolwiek prymitywne. Oczekuje się, że sam sobie poradzisz, jeśli domyślne ustawienia nie będą dla ciebie odpowiednie.

+0

Dodanie bloku 'try-execpt' nie może rozwiązać żadnego z problemów. W przypadku 'concurrent', nadal nie mogę dostać się do oryginalnego traceback po złapaniu nowego wyjątku. W przypadku 'workerpool', nigdy nie dojdę do bloku z wyjątkiem sytuacji, w której interpreter ulega awarii. W przypadku 'threadpool' nigdy nie dostaję się do bloku except, ponieważ w ogóle nie są zgłaszane żadne wyjątki. – xApple

+1

Myślisz o bloku 'try' w głównym wątku lub procesie. Mówię, że korzystasz z bloku 'try' wokół działania procesów procesów roboczych. Jeśli spodziewasz się "podnieść" wyjątek w wątku/procesie roboczym i wysłać go do głównego skryptu, musisz najpierw go przechwycić w miejscu, w którym wystąpił. – slezica

+0

Cóż, nie zamierzam pisać o obsłudze błędów dla każdej funkcji, którą chcę uruchomić. Więc mówisz, że powinienem napisać własną globalną obsługę błędów. Tak, mógłbym wybrać jedną z bibliotek i rozpocząć edycję kodu źródłowego w celu dodania funkcjonalności, ale tego właśnie chciałem uniknąć:) – xApple

Powiązane problemy