轮询子进程对象而不会阻塞

我正在编写一个python脚本,该脚本在后台启动程序,然后进行监视以查看它们是否遇到错误.我正在使用子流程模块来启动流程并保留正在运行的程序的列表.

process.append((subprocess.Popen(命令,stdin = subprocess.PIPE,stdout = subprocess.PIPE,stderr = subprocess.PIPE),命令))

我发现当我尝试通过在子进程对象上调用communication监视程序时,主程序会等待程序完成.我尝试使用poll(),但这不能使我访问导致崩溃的错误代码,我想解决此问题并重试打开进程.
runningProcesses是一个元组列表,其中包含子流程对象和与其关联的命令.

def monitorPrograms(runningProcesses):
    for program in runningProcesses:
        temp = program[0].communicate()
        if program[0].returncode:
            if program[0].returncode == 1:
                print "Program exited successfully."
            else:
                print "Whoops, something went wrong. Program %s crashed." % program[0].pid

当我尝试不使用通讯获取返回代码时,程序崩溃没有注册.
我是否必须使用线程来并行运行通信,还是缺少一种更简单的方法?

解决方法:

根据我的研究,最好的方法是使用线程.创建自己的程序包以解决此问题时引用的Here’s an article.

这里使用的基本方法是旋转线程,这些线程不断请求子进程调用的日志输出(最后是退出状态).

这是我自己的“接收器”侦听日志的示例:

class Receiver(threading.Thread):
    def __init__(self, stream, stream_type=None, callback=None):
        super(Receiver, self).__init__()
        self.stream = stream
        self.stream_type = stream_type
        self.callback = callback
        self.complete = False
        self.text = ''

    def run(self):
        for line in iter(self.stream.readline, ''):
            line = line.rstrip()
            if self.callback:
                line = self.callback(line, msg_type=self.stream_type)
            self.text += line + "\n"
        self.complete = True

现在,将接收器分离的代码:

 def _execute(self, command):
    process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                               shell=True, preexec_fn=os.setsid)
    out = Receiver(process.stdout, stream_type='out', callback=self.handle_log)
    err = Receiver(process.stderr, stream_type='err', callback=self.handle_log)
    out.start()
    err.start()
    try:
        self.wait_for_complete(out)
    except CommandTimeout:
        os.killpg(process.pid, signal.SIGTERM)
        raise
    else:
        status = process.poll()
        output = CommandOutput(status=status, stdout=out.text, stderr=err.text)
        return output
    finally:
        out.join(timeout=1)
        err.join(timeout=1)

CommandOutput只是一个命名的元组,可以轻松地引用我关心的数据.

您会注意到我有一个方法“ wait_for_complete”,它等待接收者设置complete = True.完成后,execute方法将调用process.poll()以获取退出代码.现在,我们有了所有的stdout / stderr和进程的状态代码.

上一篇:从python调用进程的最快方法?


下一篇:如何正确清理文件名(防止shell注入)?