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

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

最佳答案

虚拟任务方法是在不进行大量代码重构的情况下(避免完全返回巨大价值)的唯一方法。

问题在于工作进程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(打包的函数和发送给工作程序的参数)执行了此操作,从而避免了超出其有用范围的资源使用,并且对已经返回的内容执行相同的操作是有意义的不再相关的结果。

关于python - 垃圾收集python子进程,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54108434/

10-14 17:35
查看更多