垃圾收集 python 个子进程

Garbage collecting python subprocesses

tl;dr:我的任务具有巨大的 return 值,会消耗大量内存。我正在将它们提交给 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) 不可信,因为我无法保证我将任务发送到哪个子进程,所以唯一万无一失的方法是发送洪水以确保我关心的子流程得到一份副本。

据我所知,工作进程一完成 运行 我的任务,就没有理由保留结果。如果我的父进程将 returned 和 Future 分配给局部变量,那么任务完成后 return 值将被复制到父进程中的 Future ,这意味着工人不再需要它。如果我的父进程没有这样做,那么 return 值无论如何都会被有效丢弃。

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

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

问题是工作进程binds the result to a local name r before sending it back to the parent,只有在有新任务进来时才替换r

您可以合理地在 the CPython bug tracker 上打开一个 enhancement/bug 请求,以便在调用 _sendback_result 之后明确地让工作人员 del r;出于完全相同的原因,它已经为 call_item(打包的函数和发送给 worker 的参数)执行了此操作,以避免持有超出其 window 有用性的资源,并且这样做是有意义的对于已经返回但不再相关的结果也是如此。