Python lib psutil:如何使用wait()获取退出状态
我正在使用带有许多参数的子流程Popen执行第三方应用程序Python lib psutil:如何使用wait()获取退出状态,python,subprocess,exit-code,Python,Subprocess,Exit Code,我正在使用带有许多参数的子流程Popen执行第三方应用程序 myprocess=Popen(['executionlist','with','arguments'],stdout=PIPE,stderr=PIPE) myprocess.communicate() 获取我的stdout和err元组,第三方应用程序在后台启动,因此我在stdout中获取其pid…[如果我尝试在forground中运行,它会抛出“错误打开终端:未知”] 我正在使用psutil跟踪所有这些分叉,并使用 EXITCODE
myprocess=Popen(['executionlist','with','arguments'],stdout=PIPE,stderr=PIPE)
myprocess.communicate()
获取我的stdout和err元组,第三方应用程序在后台启动,因此我在stdout中获取其pid…[如果我尝试在forground中运行,它会抛出“错误打开终端:未知”]
我正在使用psutil跟踪所有这些分叉,并使用
EXITCODE=psutil_obj.wait(timeout=xxx)
应用程序发送不同的退出代码,我需要在EXITCODE中访问这些代码,但当我在不同的python脚本中运行它时,它总是给我“无”值
根据,,
等待()进程终止,如果进程是当前进程的子进程,则返回退出代码,否则无
我是否可以从独立的进程id访问退出代码,而不是由Popen专门分叉?您引用的文档直接告诉您,
psutil
只能获取退出代码“如果该进程是当前进程的子进程”
这才是真正的关键所在——这不是流程是否由Popen
启动,而是它是否是当前流程的子流程*
这是Unix进程模型的基础。父母必须等待他们的孩子。你不能让其他人等他们(除非重新租用)。如果父级仍在运行,则必须由它来收获它们。如果父级不再运行,则子级可能已经是一个僵尸,或者它被重新出租给父级的父级或init/launchd/等,或者成为孤儿(在不同的系统和不同的情况下,细节是不同的)。没有其他进程可以等待它们的情况
最重要的是,一旦父进程调用wait
(这是Popen.communicate
所做的),进程及其在系统进程表中的条目及其retcode可能不再存在
*也就是说,即使您没有跨进程,将
子进程
与较低级别的API(如os
或psutil
)混合使用也不是一个好主意。如果创建Popen
对象,则必须调用其wait
方法,或者调用其他类似于通信的方法。一旦你这么做了,它可能就不存在了。如果要使用os.wait
,请使用由os
中的fork/spawn/etc.方法创建的进程。如果要使用psutil.wait
,可以使用由os
或psutil.Popen
创建的进程,但不能使用子进程。Popen
引用的文档直接告诉您,psutil
只能获取退出代码“如果该进程是当前进程的子进程”
这才是真正的关键所在——这不是流程是否由Popen
启动,而是它是否是当前流程的子流程*
这是Unix进程模型的基础。父母必须等待他们的孩子。你不能让其他人等他们(除非重新租用)。如果父级仍在运行,则必须由它来收获它们。如果父级不再运行,则子级可能已经是一个僵尸,或者它被重新出租给父级的父级或init/launchd/等,或者成为孤儿(在不同的系统和不同的情况下,细节是不同的)。没有其他进程可以等待它们的情况
最重要的是,一旦父进程调用wait
(这是Popen.communicate
所做的),进程及其在系统进程表中的条目及其retcode可能不再存在
*也就是说,即使您没有跨进程,将子进程
与较低级别的API(如os
或psutil
)混合使用也不是一个好主意。如果创建Popen
对象,则必须调用其wait
方法,或者调用其他类似于通信的方法。一旦你这么做了,它可能就不存在了。如果要使用os.wait
,请使用由os
中的fork/spawn/etc.方法创建的进程。如果要使用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()
这有两个明显的局限性,但最终它们与您在尝试(例如,同时通过internet与多台机器进行通信)时处理的多路复用问题完全相同,并且它们具有相同的解决方案
首先,拥有数百个线程是不好的。它们没有做任何事情,但它们仍然有大堆栈,占用了虚拟内存空间(在32位Python中尤其糟糕),并占用了内核调度程序表中的空间(在旧的Unix中尤其糟糕)。幸运的是,如果您不关心Windows,您可以使用与处理网络代码相同的方法来解决这一问题:将子流程管道放入select
或poll
循环中。或者,如果您确实关心Windows,或者只是不想编写自己的select
loop,那么请找到一个可以为您完成所有繁重工作的框架。如果您将找到一些特定于子流程的选项
。如果您已经在使用事件驱动的网络或GUI框架,如Twisted或Qt,它很可能有自己的内置方式(例如,请参阅Twisted)
其次,您的回调
在某个任意后台线程中被调用,无法将返回值或异常传播到c语言的其余部分