我有一个在Python / PyQt / QtWebKit基础上运行的JavaScript应用程序,它创建subprocess.Popen
个对象来运行外部进程。
Popen
个对象保存在字典中并由内部标识符引用,以便JS应用程序可以通过Popen
调用pyqtSlot
的方法,例如{{1}确定进程是否仍在运行或poll()
以杀死流氓进程。
如果某个进程不再运行,我想从字典中删除它的kill()
对象以进行垃圾回收。
什么是自动清理字典以防止内存泄漏的推荐方法?
到目前为止我的想法:
Popen
以在终止时立即执行自动清理
PRO :立即清理,线程可能不会耗费太多CPU功率因为它们应该睡觉,对吧?
CON :许多线程取决于产卵活动。Popen.wait()
,并检查Popen.poll()
是否已终止并在此情况下进行清理。您会选择哪一个?为什么?或者更好的解决方案?
答案 0 :(得分:2)
对于与平台无关的解决方案,我会使用选项#2,因为高CPU使用率的“CON”可以用类似的东西来规避......
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,您应该可以通过WaitForMultipleObjects
使用ctypes
功能作为ctypes.windll.kernel32.WaitForMultipleObjects
,但您必须考虑可行性。
对于OSX和Linux,使用SIGCHLD
模块异步处理signal
可能是最简单的。
一个快速的例子......
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'