Регистрация потоков при использовании ThreadPoolExecutor - PullRequest
0 голосов
/ 22 марта 2020

Я использую ThreadPoolExecutor из python concurrent.futures, чтобы распараллелить очистку и запись результатов в базу данных. При этом я понял, что не получаю никакой информации, если один из потоков выходит из строя. Как я могу правильно знать, какие потоки выходят из строя и почему (например, с «нормальной» трассировкой)? Ниже приведен минимальный рабочий пример.

import logging
logging.basicConfig(format='%(asctime)s  %(message)s', 
    datefmt='%y-%m-%d %H:%M:%S', level=logging.INFO)
from concurrent.futures import ThreadPoolExecutor

def worker_bee(seed):
    # sido is not defined intentionally to break the code
    result = seed + sido
    return result

# uncomment next line, and you will get the usual traceback
# worker_bee(1)

# ThreadPoolExecutor will not provide any traceback
logging.info('submitting all jobs to the queue')
with ThreadPoolExecutor(max_workers=4) as executor:
    for seed in range(0,10):
        executor.submit(worker_bee, seed)
    logging.info(f'submitted, waiting for threads to finish')

Если я импортирую логирование изнутри worker_bee() и направьте сообщения в логер root, я вижу их в окончательном журнале. Но я смогу видеть только те сообщения журнала, которые я определяю, а не трассировку того, где код фактически не работает.

1 Ответ

2 голосов
/ 22 марта 2020

Вы можете получить «нормальную трассировку», получив результат из executor.submit(). Это позволит пройти некоторое время и поток (ы) начнут выполняться (и, возможно, потерпят неудачу).

Вот что я имею в виду:

from concurrent.futures import ThreadPoolExecutor
import logging

logging.basicConfig(format='%(asctime)s  %(message)s',
                    datefmt='%y-%m-%d %H:%M:%S', level=logging.INFO)

def worker_bee(seed):
    # sido is not defined intentionally to break the code
    result = seed + sido
    return result

logging.info('submitting all jobs to the queue')
with ThreadPoolExecutor(max_workers=4) as executor:
    results = []
    for seed in range(10):
        result = executor.submit(worker_bee, seed)
        results.append(result)
    logging.info(f'submitted, waiting for threads to finish')

for result in results:
    print(result.result())

Вывод:

20-03-21 16:21:24  submitting all jobs to the queue
20-03-21 16:21:24  submitted, waiting for threads to finish
Traceback (most recent call last):
  File "logging-threads-when-using-threadpoolexecutor.py", line 24, in <module>
    print(result.result())
  File "C:\Python3\lib\concurrent\futures\_base.py", line 432, in result
    return self.__get_result()
  File "C:\Python3\lib\concurrent\futures\_base.py", line 388, in __get_result
    raise self._exception
  File "C:\Python3\lib\concurrent\futures\thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "logging-threads-when-using-threadpoolexecutor.py", line 12, in worker_bee
    result = seed + sido
NameError: name 'sido' is not defined

...