子进程在终止前得到结果
subprocess get result before terminate
实时获取子进程的结果
我想在子进程终止之前实时获取每个结果 (sys.stdout
)。
假设我们有以下 file.py.
import time,sys
sys.stdout.write('something')
while True:
sys.stdout.write('something else')
time.sleep(4)
好吧,我对子进程、异步和线程模块进行了一些尝试,尽管所有方法都会在进程完成时给我结果。理想情况下,我想自己终止进程并实时获取每个结果(stdout、stderr),而不是在进程完成时。
import subprocess
proc = sp.Popen([sys.executable, "/Users/../../file.py"], stdout = subprocess.PIPE, stderr= subproces.STDOUT)
proc.communicate() #This one received the result after finish
我也在另一个线程中使用 threading
模块和 asyncio
尝试使用 readline proc.stdout.readline()
,但它也会等待直到进程完成。
我发现的唯一有用的是 psutil.Popen(*args, **kwargs)
的用法,我可以在需要进程时终止并获取一些统计信息。但主要问题仍然是在每次打印时实时(异步)获取 file.py 的每个 sys.stdout
或 print
。
*python3.6
的首选解决方案
如评论中所述,首要的事情是确保您的 file.py
程序确实按照您认为的方式写入数据。
例如,您显示的程序将在大约 40 分钟内不写入任何内容,因为这是以 4 秒为间隔发出的 14 字节打印填满 8 KB IO 缓冲区所需的时间。更令人困惑的是,如果您在 TTY 上测试某些程序(即仅 运行 它们),某些程序将 看起来 写入数据,但当您将它们作为子进程启动时则不会。这是因为在 TTY 上 stdout 是行缓冲的,而在管道上它是完全缓冲的。当输出未被刷新时,其他程序根本无法检测输出,因为它卡在子进程的缓冲区内,它从不费心与任何人共享。
换句话说,别忘了冲洗:
while True:
# or just print('something else', flush=True)
sys.stdout.write('something else')
sys.stdout.flush()
time.sleep(4)
说完这些,让我们看看如何读取那个输出。 Asyncio 为子进程提供了一个很好的基于流的接口,它能够在输出到达时访问任意输出。例如:
import asyncio
async def main():
loop = asyncio.get_event_loop()
proc = await asyncio.create_subprocess_exec(
"python", "file.py",
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
)
# loop.create_task() rather than asyncio.create_task() because Python 3.6
loop.create_task(display_as_arrives(proc.stdout, 'stdout'))
loop.create_task(display_as_arrives(proc.stderr, 'stderr'))
await proc.wait()
async def display_as_arrives(stream, where):
while True:
# 1024 chosen arbitrarily - StreamReader.read will happily return
# shorter chunks - this allows reading in real-time.
output = await stream.read(1024)
if output == b'':
break
print('got', where, ':', output)
# run_until_complete() rather than asyncio.run() because Python 3.6
asyncio.get_event_loop().run_until_complete(main())
实时获取子进程的结果
我想在子进程终止之前实时获取每个结果 (sys.stdout
)。
假设我们有以下 file.py.
import time,sys
sys.stdout.write('something')
while True:
sys.stdout.write('something else')
time.sleep(4)
好吧,我对子进程、异步和线程模块进行了一些尝试,尽管所有方法都会在进程完成时给我结果。理想情况下,我想自己终止进程并实时获取每个结果(stdout、stderr),而不是在进程完成时。
import subprocess
proc = sp.Popen([sys.executable, "/Users/../../file.py"], stdout = subprocess.PIPE, stderr= subproces.STDOUT)
proc.communicate() #This one received the result after finish
我也在另一个线程中使用 threading
模块和 asyncio
尝试使用 readline proc.stdout.readline()
,但它也会等待直到进程完成。
我发现的唯一有用的是 psutil.Popen(*args, **kwargs)
的用法,我可以在需要进程时终止并获取一些统计信息。但主要问题仍然是在每次打印时实时(异步)获取 file.py 的每个 sys.stdout
或 print
。
*python3.6
的首选解决方案如评论中所述,首要的事情是确保您的 file.py
程序确实按照您认为的方式写入数据。
例如,您显示的程序将在大约 40 分钟内不写入任何内容,因为这是以 4 秒为间隔发出的 14 字节打印填满 8 KB IO 缓冲区所需的时间。更令人困惑的是,如果您在 TTY 上测试某些程序(即仅 运行 它们),某些程序将 看起来 写入数据,但当您将它们作为子进程启动时则不会。这是因为在 TTY 上 stdout 是行缓冲的,而在管道上它是完全缓冲的。当输出未被刷新时,其他程序根本无法检测输出,因为它卡在子进程的缓冲区内,它从不费心与任何人共享。
换句话说,别忘了冲洗:
while True:
# or just print('something else', flush=True)
sys.stdout.write('something else')
sys.stdout.flush()
time.sleep(4)
说完这些,让我们看看如何读取那个输出。 Asyncio 为子进程提供了一个很好的基于流的接口,它能够在输出到达时访问任意输出。例如:
import asyncio
async def main():
loop = asyncio.get_event_loop()
proc = await asyncio.create_subprocess_exec(
"python", "file.py",
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
)
# loop.create_task() rather than asyncio.create_task() because Python 3.6
loop.create_task(display_as_arrives(proc.stdout, 'stdout'))
loop.create_task(display_as_arrives(proc.stderr, 'stderr'))
await proc.wait()
async def display_as_arrives(stream, where):
while True:
# 1024 chosen arbitrarily - StreamReader.read will happily return
# shorter chunks - this allows reading in real-time.
output = await stream.read(1024)
if output == b'':
break
print('got', where, ':', output)
# run_until_complete() rather than asyncio.run() because Python 3.6
asyncio.get_event_loop().run_until_complete(main())