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)
这有效,但是a)非常笨拙,更重要的是b)不可信,因为我无法保证我要将任务发送到哪个子流程,因此唯一安全的方法是发送泛滥以确保子流程我很想得到副本。
据我所知,一旦工作进程完成我的任务运行,就没有理由保留结果了。如果我的父进程将返回的Future
分配给局部变量,那么当任务完成时,返回值将被复制到父级的Future
中,这意味着工作人员不再需要它。如果我的父进程没有这样做,那么无论如何都将有效地放弃返回值。
我在这里误解了什么吗,或者这仅仅是子进程如何引用内存的一个不幸之处?如果是这样,是否有更好的解决方法?
答案 0 :(得分:1)
您的虚拟任务方法是在不进行大量代码重构(完全避免返回巨大价值)的情况下完成此任务的唯一方法。
问题在于工作进程binds the result to a local name r
before sending it back to the parent仅在有新任务出现时才替换r
。
您可以合理地在the CPython bug tracker上打开增强/错误请求,以在调用del r
之后使工作程序显式地_sendback_result
;出于完全相同的原因,它已经为call_item
(发送给工作程序的打包函数和参数)进行了此操作,以避免保留超出其有用范围的资源,并且对已经返回,不再有相关结果。