Я пишу функцию в Python 3.7, которая обрабатывает исключения в многопроцессорной установке путем проверки стека вызовов.
Однако я заметил, что если я укажу опцию maxtasksperchild
с объектом multiprocessing.Pool
, некоторые процессы (предположительно, созданные после того, как были убиты первые) возвращают совершенно другую трассировку стека, которая не даже пройти по вызывающей функции.
Минимальный воспроизводимый пример:
#!/usr/bin/env python3
import inspect
from multiprocessing import Pool
def mp_caller():
with Pool() as pool:
pool.map(_bork, range(10))
pool.close()
pool.join()
def mp_caller_kill():
with Pool(maxtasksperchild=1) as pool:
pool.map(_bork, range(10))
pool.close()
pool.join()
def _bork(i):
try:
if i % 3 == 0:
raise RuntimeError("BLAH")
print(i)
except:
handle_exception()
def handle_exception():
print("Stack info: {}".format(
[
f.function
for f in inspect.getouterframes(inspect.currentframe())
]
))
if __name__ == "__main__":
print("Without killing processes:")
mp_caller()
print("Killing processes:")
mp_caller_kill()
Выход:
Without killing processes:
2
Stack info: ['handle_exception', '_bork', 'mapstar', 'worker', 'run', '_bootstrap', '_launch', '__init__', '_Popen', 'start', '_repopulate_pool', '__init__', 'Pool', 'mp_caller', '<module>']
4
5
Stack info: ['handle_exception', '_bork', 'mapstar', 'worker', 'run', '_bootstrap', '_launch', '__init__', '_Popen', 'start', '_repopulate_pool', '__init__', 'Pool', 'mp_caller', '<module>']
7
8
Stack info: ['handle_exception', '_bork', 'mapstar', 'worker', 'run', '_bootstrap', '_launch', '__init__', '_Popen', 'start', '_repopulate_pool', '__init__', 'Pool', 'mp_caller', '<module>']
1
Stack info: ['handle_exception', '_bork', 'mapstar', 'worker', 'run', '_bootstrap', '_launch', '__init__', '_Popen', 'start', '_repopulate_pool', '__init__', 'Pool', 'mp_caller', '<module>']
Killing processes:
2
Stack info: ['handle_exception', '_bork', 'mapstar', 'worker', 'run', '_bootstrap', '_launch', '__init__', '_Popen', 'start', '_repopulate_pool', '__init__', 'Pool', 'mp_caller_kill', '<module>']
1
Stack info: ['handle_exception', '_bork', 'mapstar', 'worker', 'run', '_bootstrap', '_launch', '__init__', '_Popen', 'start', '_repopulate_pool', '__init__', 'Pool', 'mp_caller_kill', '<module>']
4
5
Stack info: ['handle_exception', '_bork', 'mapstar', 'worker', 'run', '_bootstrap', '_launch', '__init__', '_Popen', 'start', '_repopulate_pool', '_maintain_pool', '_handle_workers', 'run', '_bootstrap_inner', '_bootstrap']
7
8
Stack info: ['handle_exception', '_bork', 'mapstar', 'worker', 'run', '_bootstrap', '_launch', '__init__', '_Popen', 'start', '_repopulate_pool', '_maintain_pool', '_handle_workers', 'run', '_bootstrap_inner', '_bootstrap']
Обратите внимание на последние два списка стека, которые расходятся в _maintain_pool
и в которых отсутствует интересующая меня функция mp_caller_kill
.
Есть ли способ добраться до нужного стека, или эти процессы полностью разделены? Мне нужно использовать maxtasksperchild
, поскольку зависимая библиотека C не освобождает память.
Спасибо.