Где утечка памяти? Как отключать потоки во время многопроцессорной обработки в python?
Непонятно, как правильно таймаутировать рабочих joblib Parallel
в python. У других были похожие вопросы здесь, здесь, здесь и здесь.
В моем примере я использую пул из 50 joblib
рабочих с бэкэндом threading
.
Параллельный вызов (threading):
output = Parallel(n_jobs=50, backend = 'threading')
(delayed(get_output)(INPUT)
for INPUT in list)
Здесь Parallel
зависает без ошибок, как только len(list) <= n_jobs
, но только когда n_jobs => -1
.
Чтобы обойти эту проблему, люди дают инструкции о том, как создать декоратор тайм-аута функции Parallel
(get_output(INPUT)
) в приведенном выше примере), используя multiprocessing
:
Основная функция (оформлена):
@with_timeout(10) # multiprocessing
def get_output(INPUT): # threading
output = do_stuff(INPUT)
return output
Многообъемный декоратор:
def with_timeout(timeout):
def decorator(decorated):
@functools.wraps(decorated)
def inner(*args, **kwargs):
pool = multiprocessing.pool.ThreadPool(1)
async_result = pool.apply_async(decorated, args, kwargs)
try:
return async_result.get(timeout)
except multiprocessing.TimeoutError:
return
return inner
return decorator
Добавление декоратора к другому рабочему коду приводит к утечке памяти после ~ 2x длины таймаута плюс крушение затмения.
Где эта утечка в декораторе?
Как отключить потоки во время многопроцессорной обработки в python?
Ответы
Ответ 1
Невозможно убить Thread в Python без взлома.
Утечка памяти, которую вы испытываете, связана с накоплением потоков, которые, по вашему мнению, были убиты. Чтобы доказать это, попробуйте проверить количество потоков, в которых работает ваше приложение, вы увидите, что они медленно растут.
Под капотом нить ThreadPool
не заканчивается, а продолжает функционировать до конца.
Причина, по которой нить не может быть убита, связана с тем, что потоки совместно используют память с родительским процессом. Поэтому очень сложно убить поток, гарантируя целостность памяти вашего приложения.
Java-разработчики уже давно рассмотрели .
Если вы можете запускать свою функцию в отдельном процессе, тогда вы можете легко полагаться на логику тайм-аута, где сам процесс убивается после достижения таймаута.
Библиотека Pebble
уже предлагает декораторы с таймаутом.