垃圾收集python子进程

时间:2019-01-09 10:51:03

标签: python concurrent.futures

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中,这意味着工作人员不再需要它。如果我的父进程没有这样做,那么无论如何都将有效地放弃返回值。

我在这里误解了什么吗,或者这仅仅是子进程如何引用内存的一个不幸之处?如果是这样,是否有更好的解决方法?

1 个答案:

答案 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(发送给工作程序的打包函数和参数)进行了此操作,以避免保留超出其有用范围的资源,并且对已经返回,不再有相关结果。