关于这篇文章:Python del Statement,
我最近遇到了以下代码段:
# custom_process.py
import threading
import subprocess
myList = [] # module-wide list
class Foo(threading.Thread):
myprocess = None
returncode = None
def run(self):
self.myprocess = subprocess.Popen(...)
global myList
myList.append(self.myprocess)
... # Code skipped for brevity
self.returncode = self.myprocess.returncode
tmp1, tmp2 = self.myprocess.communicate()
... # Code skipped for brevity
del self.myprocess
此代码在连续调用到Foo
的{{1}}方法时,耗尽系统上的可用文件描述符会抛出异常:run
。
因此我想知道......在处理子进程对象时,文件描述符是否与实际的OS进程一起关闭,或者当Python子进程对象的引用计数变为零时?
提前致谢。
答案 0 :(得分:2)
是的,del
只会移除对象的引用,它的名称将会如此。要从列表中删除项目,您需要使用不同的语法。
>>> a = 10
>>> l = [a]
>>> del a
>>> a # the name a will be gone now
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> l # but the list will still contain 10
[10]
>>> del l[0]
>>> l # but now it is gone
[]
>>>
或者,您可以致电l.remove(a)
。
答案 1 :(得分:1)
Popen启动一个新的OS进程,并返回一个可用于与之交互的python对象。
这两个仍然是分开的,删除python对象并不一定会影响单独的运行过程,它只是删除了一种方便的与它交互的方式。
对于python Popen对象在进程终止后留下来是完全合理的,反之亦然。
行为将取决于Popen的论据,例如,即使整个脚本终止,也可以将进程配置为继续运行。
如果是一次性过程,它应该在communicate()
调用后终止,但是您应该在此次调用后检查返回代码以进行验证(或使用poll()
检查是否& #39; s活着)。
也可能需要一段时间才能终止,如果你是每秒调用此函数1000次,你可能比他们终止更快地启动它们,导致FD耗尽。
答案 2 :(得分:1)
我发现了一篇很好的博客文章,描述了我所面临的情况:
How subprocess and file descriptors work in Python
通过强调* nixes和Windows之间的文件处理差异,直观地解决问题。作者甚至提出了一个解决方案!绝对值得一读。
答案 3 :(得分:0)
在保留进程列表的同时避免fd耗尽的最佳方法是使用进程池。这样,您可以限制同时打开的进程数,只有在前一个进程结束时才会启动新进程。
https://docs.python.org/3.4/library/multiprocessing.html#using-a-pool-of-workers
当然,其他两个答案都是关于引用删除以及为什么会出现内存耗尽的原因,这就是为什么我不在这里重复它。
答案 4 :(得分:0)
您可以使用 myprocess.kill()或 myprocess.terminate()来关闭正在运行的进程 - 如果您在退出时不需要它run()方法。 (你的片段意味着你没有)
如果您也不将其添加为属性并且不将其添加到 myList (通过您的代码,它是多余的),它将在您退出后立即销毁run() - 在Python中,你通常依靠垃圾收集器而实际使用 del 运算符很少