Вкратце: у меня есть задачи с огромными возвращаемыми значениями, которые потребляют много памяти. Я отправляю их на 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
в родительском процессе, что означает, что рабочему процессу это больше не нужно. Если мой родительский процесс этого не сделал, то возвращаемое значение все равно отбрасывается.
Я что-то неправильно понимаю, или это просто неудачная причуда того, как подпроцессы ссылаются на память? Если да, то есть ли лучший обходной путь?