Python库psutil:如何使用wait()获取退出状态



我正在使用带有许多参数的子进程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/等。或者被孤立(不同系统和不同情况下的细节不同)。不存在其他进程可以等待它们的情况。

最重要的是,一旦父级调用waitPopen.communicate就是这样做的),进程及其在系统进程表中的条目及其返回代码可能就不存在了。


*也就是说,即使您没有跨流程,将subprocess与较低级别的API(如ospsutil)混合也是个坏主意。如果创建一个Popen对象,则必须调用它的wait方法,或者其他为您执行此操作的方法,如communicate。一旦你这样做了,它可能就不存在了。如果您想使用os.wait,请使用fork/spawn等创建的进程。方法在CCD_ 12中。如果要使用psutil.wait,可以使用ospsutil.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,您可以像处理网络代码一样绕过它:将子流程管道放入selectpoll循环中。或者,如果您确实关心Windows,或者只是不想编写自己的select循环,请找到一个能为您完成所有繁重任务的框架。如果您在PyPI中搜索"子流程",您会发现一些特定于subprocess的选项。如果您已经在使用事件驱动的网络或GUI框架,如Twisted或Qt,那么它很可能有自己的内置方法(例如,请参阅使用Twisted的进程)。

其次,您的callback在某个任意后台线程中被调用,并且除了更改一些共享值之外,无法将返回值或异常传播到代码的其余部分。这意味着你现在正在处理共享数据线程的所有常见头痛问题,尽管你从未要求这样做。所有改善这种情况的常用方法——queueconcurrent.futures等——也适用于此。


当然,如果你幸运的话,你一次只有十几个进程在运行(所以第一个问题不是问题),而你在回调中所想做的就是打印或记录一些数据(所以第二个问题也不是问题)。

最新更新