在Windows上的Python 3.4中,我需要通过子进程流式传输写入stdout / stderr的数据,即使用Python 3.4中引入的asyncio框架接收其输出。之后我还必须确定程序的退出代码。我怎么能这样做?
答案 0 :(得分:6)
到目前为止,我提出的解决方案是使用SubprocessProtocol来接收来自子进程的输出,以及用于获取进程的相关传输'退出代码。我不知道这是否是最佳的。我的方法基于answer to a similar question by J.F. Sebastian。
import asyncio
import contextlib
import os
import locale
class SubprocessProtocol(asyncio.SubprocessProtocol):
def pipe_data_received(self, fd, data):
if fd == 1:
name = 'stdout'
elif fd == 2:
name = 'stderr'
text = data.decode(locale.getpreferredencoding(False))
print('Received from {}: {}'.format(name, text.strip()))
def process_exited(self):
loop.stop()
if os.name == 'nt':
# On Windows, the ProactorEventLoop is necessary to listen on pipes
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
with contextlib.closing(loop):
# This will only connect to the process
transport = loop.run_until_complete(loop.subprocess_exec(
SubprocessProtocol, 'python', '-c', 'print(\'Hello async world!\')'))[0]
# Wait until process has finished
loop.run_forever()
print('Program exited with: {}'.format(transport.get_returncode()))
答案 1 :(得分:1)
由于事件循环可能会在读取之前看到并通知进程退出 对于stdout / stderr的剩余数据,我们需要检查PIPE关闭事件 除了流程退出事件。
这是对aknuds1答案的更正:
class SubprocessProtocol(asyncio.SubprocessProtocol):
def __init__(self):
self._exited = False
self._closed_stdout = False
self._closed_stderr = False
@property
def finished(self):
return self._exited and self._closed_stdout and self._closed_stderr
def signal_exit(self):
if not self.finished:
return
loop.stop()
def pipe_data_received(self, fd, data):
if fd == 1:
name = 'stdout'
elif fd == 2:
name = 'stderr'
text = data.decode(locale.getpreferredencoding(False))
print('Received from {}: {}'.format(name, text.strip()))
def pipe_connection_lost(self, fd, exc):
if fd == 1:
self._closed_stdout = True
elif fd == 2:
self._closed_stderr = True
self.signal_exit()
def process_exited(self):
self._exited = True
self.signal_exit()
答案 2 :(得分:0)
我想使用high-level api:
proc = yield from asyncio.create_subprocess_exec(
'python', '-c', 'print(\'Hello async world!\')')
stdout, stderr = yield from proc.communicate()
retcode = proc.returncode
你还可以做更多:
yield from proc.stdin.write(b'data')
yield from proc.stdin.drain()
stdout = yield from proc.stdout.read()
stderr = yield from proc.stderr.read()
retcode = yield from proc.wait()
等等。
但是,请记住,当孩子进程没有打印任何内容时,请等待,例如,stdout
可以挂起你的协程。