tl; dr: у меня есть задачи с огромными возвращаемыми значениями, которые занимают много памяти. Я отправляю их на concurrent.futures.ProcessPoolExecutor
. Подпроцессы удерживают память до тех пор, пока не получат новое задание. Как заставить подпроцессы эффективно собирать мусор?
Пример
import concurrent.futures
import time
executor = concurrent.futures.ProcessPoolExecutor(max_workers=1)
def big_val():
return [{1:1} for i in range(1, 1000000)]
future = executor.submit(big_val)
# do something with future result
В приведенном выше примере я создаю большой объект в подпроцессе, а затем работаю с результатом. С этого момента я могу работать с памятью в родительском процессе, но подпроцесс, созданный моим ProcessPoolExecutor, будет удерживать память, выделенную для моей задачи, бесконечно.
Что я пробовал
Честно говоря, единственное, о чем я могу подумать, это подать фиктивное задание:
def donothing():
pass
executor.submit(donothing)
Это работает, но это а) довольно неуклюже и, что более важно, б) ненадежно, потому что у меня нет гарантий, в какой подпроцесс я отправляю задачи, поэтому единственный надежный способ - отправить флуд, чтобы гарантировать подпроцессы Я забочусь о том, чтобы получить копию.
Насколько я могу судить, как только рабочий процесс завершил выполнение моей задачи, у него нет причин удерживать результат. Если мой родительский процесс назначил возвращенную Future
локальной переменной, то в момент завершения задачи возвращаемое значение будет скопировано в Future
в родительской переменной, что означает, что работник больше не нуждается в этом. Если мой родительский процесс этого не сделал, то возвращаемое значение в любом случае фактически отбрасывается.
Я что-то здесь неправильно понимаю, или это просто прискорбное измышление того, как подпроцессы ссылаются на память? Если да, то есть ли лучший обходной путь?