Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在进程终止时清理subprocess.Popen实例_Python_Python 3.x_Pyqt_Subprocess_Qtwebkit - Fatal编程技术网

Python 如何在进程终止时清理subprocess.Popen实例

Python 如何在进程终止时清理subprocess.Popen实例,python,python-3.x,pyqt,subprocess,qtwebkit,Python,Python 3.x,Pyqt,Subprocess,Qtwebkit,我有一个JavaScript应用程序运行在Python /pyqt/qtWebKek基础上,创建了子进程。Popen < /Cord>对象运行外部进程。< /P> Popen对象保存在字典中,并由内部标识符引用,因此JS应用程序可以通过pyqtlot调用Popen的方法,例如poll()来确定进程是否仍在运行,或者kill()来杀死恶意进程 如果进程不再运行,我想从字典中删除它的Popen对象以进行垃圾收集 建议采用什么方法自动清理字典以防止内存泄漏 到目前为止,我的想法是: 在每个衍生进程的

我有一个JavaScript应用程序运行在Python /pyqt/qtWebKek基础上,创建了<代码>子进程。Popen < /Cord>对象运行外部进程。< /P>
Popen
对象保存在字典中,并由内部标识符引用,因此JS应用程序可以通过
pyqtlot
调用
Popen
的方法,例如
poll()
来确定进程是否仍在运行,或者
kill()
来杀死恶意进程

如果进程不再运行,我想从字典中删除它的
Popen
对象以进行垃圾收集

建议采用什么方法自动清理字典以防止内存泄漏

到目前为止,我的想法是:

  • 在每个衍生进程的线程中调用
    Popen.wait()
    ,以便在终止时立即执行自动清理。
    PRO:即时清理,线程可能不会消耗太多CPU电量,因为它们应该处于休眠状态,对吗?
    CON:许多线程取决于生成活动
  • 使用线程调用所有现有进程上的
    Popen.poll()
    ,并检查
    returncode
    是否已终止并清除这些进程。
    PRO:所有进程只需一个工作线程,内存使用率更低。
    CON:需要定期轮询,如果有许多长时间运行的进程或大量生成的已处理进程,则CPU使用率更高

你会选择哪一个?为什么?或者有更好的解决方案吗?

对于平台无关的解决方案,我会选择选项2,因为高CPU使用率的“弊病”可以通过以下方式避免

import time

# Assuming the Popen objects are in the dictionary values
PROCESS_DICT = { ... }

def my_thread_main():
    while 1:
        dead_keys = []
        for k, v in PROCESS_DICT.iteritems():
            v.poll()
            if v.returncode is not None:
                dead_keys.append(k)
        if not dead_keys:
            time.sleep(1)  # Adjust sleep time to taste
            continue
        for k in dead_keys:
            del PROCESS_DICT[k]
…因此,如果迭代中没有进程死亡,您只需睡一会儿

因此,实际上,您的线程大部分时间仍处于睡眠状态,尽管子进程死亡和随后的“清理”之间存在潜在的延迟,但这并不是什么大问题,而且这应该比每个进程使用一个线程扩展得更好

不过,还有更好的平台相关解决方案

对于Windows,您应该能够通过as
ctypes.windell.kernel32.WaitForMultipleObjects
使用该函数,尽管您必须研究其可行性

对于OSX和Linux,可能最容易使用模块异步处理

一个肮脏的例子

import os
import time
import signal
import subprocess

# Map child PID to Popen object
SUBPROCESSES = {}

# Define handler
def handle_sigchld(signum, frame):
    pid = os.wait()[0]
    print 'Subprocess PID=%d ended' % pid
    del SUBPROCESSES[pid]

# Handle SIGCHLD
signal.signal(signal.SIGCHLD, handle_sigchld)

# Spawn a couple of subprocesses
p1 = subprocess.Popen(['sleep', '1'])
SUBPROCESSES[p1.pid] = p1
p2 = subprocess.Popen(['sleep', '2'])
SUBPROCESSES[p2.pid] = p2

# Wait for all subprocesses to die
while SUBPROCESSES:
    print 'tick'
    time.sleep(1)

# Done
print 'All subprocesses died'

这需要在什么操作系统上工作?主要是Windows、Mac OS X,如果可能的话,最好是Linux。最好是平台无关的解决方案。好吧,我给出的答案将适用于Linux和OSX。我必须考虑一下Windows解决方案。好的,谢谢你,我忘了提到这是Python3.3.1更新版的答案。代码示例适用于Python2.x,但对于3.x-compat,您只需将
print foo
更改为
print(foo)
。是的,我一直在考虑使用
WaitForMultipleObjects()
,不过解决方案可能有点复杂。。。每次添加新进程时,您可能都必须更新等待进程,这可能不值得付出努力,例如,在循环中,使用几秒钟的等待超时或其他方式。此外,由于
最大等待对象数
的限制,您可能需要将等待分为多个线程。@Archimedix是的。这与在多个文件描述符上使用非常相似-通常的习惯用法是包含FD(通常是侦听套接字),这可能会更改您正在监视的FD集。因此,在您的情况下,您需要在集合中包含一些对象,这些对象可用于检测何时创建新进程,然后等待超时可能会很长。不过,唯一的好处是从选项2中删除延迟。(在下一篇评论中继续)@Archimedix(在上一篇评论中继续)
SIGCHLD
解决方案似乎是最优雅的,它是异步的(即不需要阻塞调用),可以在主线程中使用。它也可以在Windows上使用,只要您的代码将在为编译的Python版本下运行,但如果您使用多个第三方Python扩展模块,这可能会更加复杂。我建议现在使用选项#2,因为它不需要太多的线程管理,如果有必要的话,以后再考虑优化。@Archimedix我刚刚遇到了一个使用WMI的异步Windows选项-但不确定适应Python有多容易。谢谢,我认为WMI太麻烦了。