我正在使用带有许多参数的子进程Popen执行第三方应用程序
myprocess=Popen(['executionlist','with','arguments'],stdout=PIPE,stderr=PIPE)
myprocess.communicate()
获取stdout的元组,第三方应用程序在后台启动,所以我在stdout中获取它的pid。。。[如果我试图在forground中运行,它会抛出"打开终端时出错:未知"]我正在使用psutil来跟踪所有这些分叉,并使用进行监控
EXITCODE=psutil_obj.wait(timeout=xxx)
应用程序发送不同的退出代码,我需要在EXITCODE中访问这些代码,但当我在不同的python脚本中运行它时,它总是给我"None"值。。。。
根据,https://code.google.com/p/psutil/wiki/Documentation等待进程终止,如果进程是当前进程的子进程,也返回退出代码,否则无
我是否可以从独立进程id访问退出代码,而不是由Popen专门派生?
您引用的文档直截了当地告诉您,psutil
只能获得退出代码"如果进程是当前进程的子进程"。
这才是真正的关键——这不是进程是否由Popen
启动,而是它是否是当前进程的子进程。*
这是Unix进程模型的基础。父母必须等待他们的孩子。你不能让其他人等他们(除非重新安排他们)。如果父母还在跑步,那就必须是收获他们的人。如果父级不再运行,则子级已经是僵尸,或者它将被重新分配给父级的父级或init/launchd/等。或者被孤立(不同系统和不同情况下的细节不同)。不存在其他进程可以等待它们的情况。
最重要的是,一旦父级调用wait
(Popen.communicate
就是这样做的),进程及其在系统进程表中的条目及其返回代码可能就不存在了。
*也就是说,即使您没有跨流程,将subprocess
与较低级别的API(如os
或psutil
)混合也是个坏主意。如果创建一个Popen
对象,则必须调用它的wait
方法,或者其他为您执行此操作的方法,如communicate
。一旦你这样做了,它可能就不存在了。如果您想使用os.wait
,请使用fork/spawn等创建的进程。方法在CCD_ 12中。如果要使用psutil.wait
,可以使用os
或psutil.Popen
创建的进程,但不能使用subprocess.Popen
创建的进程。
在反复讨论了一些评论之后,我怀疑你实际上想做这样的事情:
在主程序中,"激发并忘记"一些背景过程。但稍后,在同一个程序中,每当这些进程中的每一个真正完成时,运行一些代码来访问进程的返回代码(可能还有输出)。
这里有一个这样做的例子,通过为每个后台进程使用一个观察线程:
import subprocess
import threading
def doit(arglist, callback):
def threadfunc():
p = subprocess.Popen(arglist,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
callback(out, err, p.returncode)
t = threading.Thread(target=threadfunc)
t.start()
这有两个明显的局限性,但最终它们与您在尝试(例如,同时通过互联网与许多机器交谈)时处理的多路复用问题完全相同,并且它们有相同的解决方案。
首先,拥有数百个线程是不好的。它们没有做任何事情,但它们仍然有很大的堆栈,这些堆栈会占用你的虚拟内存空间(在32位Python中尤其糟糕),并占用内核调度程序表中的空间(在旧的Unix中特别糟糕)。幸运的是,如果您不关心Windows,您可以像处理网络代码一样绕过它:将子流程管道放入select
或poll
循环中。或者,如果您确实关心Windows,或者只是不想编写自己的select
循环,请找到一个能为您完成所有繁重任务的框架。如果您在PyPI中搜索"子流程",您会发现一些特定于subprocess
的选项。如果您已经在使用事件驱动的网络或GUI框架,如Twisted或Qt,那么它很可能有自己的内置方法(例如,请参阅使用Twisted的进程)。
其次,您的callback
在某个任意后台线程中被调用,并且除了更改一些共享值之外,无法将返回值或异常传播到代码的其余部分。这意味着你现在正在处理共享数据线程的所有常见头痛问题,尽管你从未要求这样做。所有改善这种情况的常用方法——queue
、concurrent.futures
等——也适用于此。
当然,如果你幸运的话,你一次只有十几个进程在运行(所以第一个问题不是问题),而你在回调中所想做的就是打印或记录一些数据(所以第二个问题也不是问题)。