【发布时间】:2019-08-01 16:06:02
【问题描述】:
在 python (3.7+) 中,我尝试将子进程作为上下文管理器运行,同时异步流式传输潜在的大量标准输出。问题是我似乎无法让 contextmanager 的主体与 stdout 回调异步运行。我曾尝试使用线程,在那里运行异步函数,但后来我无法弄清楚如何将 Process 对象返回到 contextmanager。
所以问题是:如何在主线程运行时从主线程中的上下文管理器产生异步进程对象?也就是说,我想在 open_subprocess() 在下面的代码中完成运行之前从它产生已经和当前正在运行的进程。
import asyncio
import contextlib
async def read_stream(proc, stream, callback):
while proc.returncode is None:
data = await stream.readline()
if data:
callback(data.decode().rstrip())
else:
break
async def stream_subprocess(cmd, *args, stdout_callback=print):
proc = await asyncio.create_subprocess_exec(
cmd,
*args,
stdout=asyncio.subprocess.PIPE)
read = read_stream(proc, proc.stdout, stdout_callback)
await asyncio.wait([read])
return proc
@contextlib.contextmanager
def open_subprocess(cmd, *args, stdout_callback=print):
proc_coroutine = stream_subprocess(
cmd,
*args,
stdout_callback=stdout_callback)
# The following blocks until proc has finished
# I would like to yield proc while it is running
proc = asyncio.run(proc_coroutine)
yield proc
proc.terminate()
if __name__ == '__main__':
import time
def stdout_callback(data):
print('STDOUT:', data)
with open_subprocess('ping', '-c', '4', 'localhost',
stdout_callback=stdout_callback) as proc:
# The following code only runs after proc completes
# but I would expect these print statements to
# be interleaved with the output from the subprocess
for i in range(2):
print(f'RUNNING SUBPROCESS {proc.pid}...')
time.sleep(1)
print(f'RETURN CODE: {proc.returncode}')
【问题讨论】:
-
你需要 asynccontextmanager docs.python.org/3/library/…
-
@altunyurt 这看起来确实很有希望,但是等待对
asyncio.create_subprocess_exec()的调用会阻塞并阻止进入 asynccontextmanager。
标签: python python-3.x subprocess python-asyncio contextmanager