2013-08-16 2 views
2

tl; dr Я создаю 3 потока, каждая нить генерирует исключение, большинство pythonic способ поднять все 3 исключения?Получение нескольких исключений из потоков в Python

Ниже приведен пример кода, аналогичный тому, что я делаю.

from multiprocessing.pool import ThreadPool 

def fail_func(host): 
    raise Exception('{} FAILED!!!'.format(host)) 

hosts = ['172.1.1.1', '172.1.1.2', '172.1.1.3'] 
pool = ThreadPool(processes=5) 
workers = [pool.apply_async(fail_func(host)) for host in hosts] 
# join and close thread pool 
pool.join(); pool.close() 
# get the exceptions 
[worker.get() for worker in workers if not worker.successful()] 

Что это заканчивает тем, что делает это просто провал на 1 хост со следующим TRACEBACK:

Но я хочу, чтобы это сделать, это поднять несколько исключений для каждого из потоков, которые не удалось, как и :

Traceback (most recent call last): 
    File "thread_exception_example.py", line 8, in <module> 
    workers = [pool.apply_async(fail_func(host)) for host in hosts] 
    File "thread_exception_example.py", line 4, in fail_func 
    raise Exception('{} FAILED!!!'.format(host)) 
Exception: 172.1.1.1 FAILED!!! 

Traceback (most recent call last): 
    File "thread_exception_example.py", line 8, in <module> 
    workers = [pool.apply_async(fail_func(host)) for host in hosts] 
    File "thread_exception_example.py", line 4, in fail_func 
    raise Exception('{} FAILED!!!'.format(host)) 
Exception: 172.1.1.2 FAILED!!! 

Traceback (most recent call last): 
    File "thread_exception_example.py", line 8, in <module> 
    workers = [pool.apply_async(fail_func(host)) for host in hosts] 
    File "thread_exception_example.py", line 4, in fail_func 
    raise Exception('{} FAILED!!!'.format(host)) 
Exception: 172.1.1.3 FAILED!!! 

Есть ли какой-нибудь питонический способ сделать это? или мне нужно обернуть все в try/except, собрать все сообщения, а затем повторно создать одно исключение?

+0

В качестве побочного примечания, это немного запутанно называть ваши объекты результатов «работником». Обычно это слово относится к подпроцессам в пуле. – abarnert

+0

В качестве еще одной заметки «multiprocessing.pool.ThreadPool» является недокументированной функцией, а «multiprocessing.dummy.Pool» документирован и должен предоставить вам то, что вы хотите. Я лично считаю, что в этом случае гораздо более ясное название 'ThreadPool' и' dummy.Pool' перевешивает это, но это стоит знать выбор для себя. – abarnert

ответ

2

Невозможно «поднять несколько исключений». В данном контексте исключения есть либо исключение, либо нет.

Итак, вам нужно создать исключение обертки, которое содержит все исключения и поднять его. Но вы чуть не весь код, вам нужно:

def get_exception(): 
    try: 
     worker.get() 
    except Exception as e: 
     return e 

Теперь, вместо того, чтобы:

[worker.get() for worker in workers if not worker.successful()] 

... вы можете просто сделать:

[get_exception(worker.get) for worker in workers if not worker.successful()] 

И вот список исключений ,


Лично я всегда думал, что AsyncResult должен иметь exception метод, похожий на тот, в concurrent.futures.Future. Но тогда я бы использовал futures здесь, в первую очередь (установка backport, если бы я был вынужден использовать Python 2.x).

Смежные вопросы