不阻塞地轮询子进程对象
Polling subprocess object without blocking
我正在编写一个 python 脚本,它在后台启动程序,然后监视它们是否遇到错误。我正在使用子进程模块启动进程并保留 运行ning 程序列表。
processes.append((subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE), command))
我发现当我尝试通过调用子进程对象上的通信来监视程序时,主程序等待程序完成。我曾尝试使用 poll(),但这无法让我访问导致崩溃的错误代码,我想解决该问题并重试打开该进程。
运行ningProcesses 是一个包含子进程对象和与之关联的命令的元组列表。
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
当我试图在不使用通信的情况下获取return代码时,程序崩溃没有注册。
我是否必须使用线程来 运行 并行通信,还是我缺少更简单的方法?
根据我的研究,执行此操作的最佳方法是 使用线程。 Here's an article 我在创建自己的包以解决此问题时引用的。
这里使用的基本方法是旋转不断请求子进程调用的日志输出(最后是退出状态)的线程。
这是我自己的 "receiver" 监听日志的示例:
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 和进程的状态代码。
无需使用线程来监视多个进程,特别是如果您不使用它们的输出(使用 DEVNULL
instead of PIPE
to hide the output), see Python threading multiple bash subprocesses?
您的主要问题是 Popen.poll()
用法不正确。如果是returnsNone
;这意味着该过程仍然是 运行——您应该调用它直到获得非 None 值。这与您的情况类似 code example that prints ping
processes statuses.
如果您确实想获取子进程' stdout/stderr 作为字符串,那么您可以使用 threads, async.io.
如果您在 Unix 上并且控制所有可能产生子进程的代码,那么您可以避免轮询并自己处理 SIGCHLD
。 asyncio
stdlib 库可以处理 SIGCHLD
。你也可以 .
我正在编写一个 python 脚本,它在后台启动程序,然后监视它们是否遇到错误。我正在使用子进程模块启动进程并保留 运行ning 程序列表。
processes.append((subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE), command))
我发现当我尝试通过调用子进程对象上的通信来监视程序时,主程序等待程序完成。我曾尝试使用 poll(),但这无法让我访问导致崩溃的错误代码,我想解决该问题并重试打开该进程。 运行ningProcesses 是一个包含子进程对象和与之关联的命令的元组列表。
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
当我试图在不使用通信的情况下获取return代码时,程序崩溃没有注册。 我是否必须使用线程来 运行 并行通信,还是我缺少更简单的方法?
根据我的研究,执行此操作的最佳方法是 使用线程。 Here's an article 我在创建自己的包以解决此问题时引用的。
这里使用的基本方法是旋转不断请求子进程调用的日志输出(最后是退出状态)的线程。
这是我自己的 "receiver" 监听日志的示例:
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 和进程的状态代码。
无需使用线程来监视多个进程,特别是如果您不使用它们的输出(使用 DEVNULL
instead of PIPE
to hide the output), see Python threading multiple bash subprocesses?
您的主要问题是 Popen.poll()
用法不正确。如果是returnsNone
;这意味着该过程仍然是 运行——您应该调用它直到获得非 None 值。这与您的情况类似 code example that prints ping
processes statuses.
如果您确实想获取子进程' stdout/stderr 作为字符串,那么您可以使用 threads, async.io.
如果您在 Unix 上并且控制所有可能产生子进程的代码,那么您可以避免轮询并自己处理 SIGCHLD
。 asyncio
stdlib 库可以处理 SIGCHLD
。你也可以