轮询子进程在循环 stdout 时完成
Poll subprocess finished while looping stdout
我正在编写一个生成大小不可预测的输出的脚本,我想在脚本完成时从循环内部知道。
这是代码:
#!/usr/bin/env python3
import subprocess
import shlex
def main():
cmd = 'bash -c "for i in $(seq 1 15);do echo $i ;sleep 1;done"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE,
universal_newlines=True)
for line in p.stdout:
print(f"file_name: {line.strip()}")
print(p.poll())
if __name__ == "__main__":
main()
即使在上一次迭代中,p.poll()
也始终是 None
,这是有道理的,因为在 echo
之后,它 sleep
s 持续 1 秒,然后才移动到下一个迭代并完成。
有什么办法让它起作用吗?
你已经确定了问题所在,即子进程在输出最后一行后仍会继续运行一秒钟,因此当程序在循环中时,程序将始终被视为运行ning。即使您将调用移到循环外的 poll
,您也可能需要稍等片刻,让子进程有机会在输出其最终消息后终止(我已经减小了循环大小——生命太短暂):
#!/usr/bin/env python3
import subprocess
import shlex
import time
def main():
cmd = 'bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, universal_newlines=True)
for line in p.stdout:
print(f"file_name: {line.strip()}", flush=True)
print(p.poll())
time.sleep(.1)
print(p.poll())
if __name__ == "__main__":
main()
打印:
bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"
file_name: 1
file_name: 2
file_name: 3
file_name: 4
file_name: 5
None
0
要在循环内“让它工作”需要对子进程内发生的事情有特殊的了解。根据上一段代码,我们需要:
#!/usr/bin/env python3
import subprocess
import shlex
import time
def main():
cmd = 'bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, universal_newlines=True)
for line in p.stdout:
# has to be greater than the sleep time in the subprocess to give the subprocess a chance to terminate
print(f"file_name: {line.strip()}", flush=True)
time.sleep(1.1)
print(p.poll())
if __name__ == "__main__":
main()
打印:
bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"
file_name: 1
None
file_name: 2
None
file_name: 3
None
file_name: 4
None
file_name: 5
0
但这不是一个切实可行的解决方案。人们将不得不问进行此轮询的原因是什么?它不提供任何有用的信息,除非您愿意在读取后包含 sleep
调用 ,因为在子进程完成最后一次写入及其终止后总会有一些延迟 ,并且这些 sleep
调用通常是浪费的。您应该一直阅读直到没有更多输出,然后执行 p.wait()
以等待子进程终止,但这是您的选择:
#!/usr/bin/env python3
import subprocess
import shlex
def main():
cmd = 'bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, universal_newlines=True)
for line in p.stdout:
print(f"file_name: {line.strip()}", flush=True)
p.wait()
if __name__ == "__main__":
main()
我正在编写一个生成大小不可预测的输出的脚本,我想在脚本完成时从循环内部知道。
这是代码:
#!/usr/bin/env python3
import subprocess
import shlex
def main():
cmd = 'bash -c "for i in $(seq 1 15);do echo $i ;sleep 1;done"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE,
universal_newlines=True)
for line in p.stdout:
print(f"file_name: {line.strip()}")
print(p.poll())
if __name__ == "__main__":
main()
即使在上一次迭代中,p.poll()
也始终是 None
,这是有道理的,因为在 echo
之后,它 sleep
s 持续 1 秒,然后才移动到下一个迭代并完成。
有什么办法让它起作用吗?
你已经确定了问题所在,即子进程在输出最后一行后仍会继续运行一秒钟,因此当程序在循环中时,程序将始终被视为运行ning。即使您将调用移到循环外的 poll
,您也可能需要稍等片刻,让子进程有机会在输出其最终消息后终止(我已经减小了循环大小——生命太短暂):
#!/usr/bin/env python3
import subprocess
import shlex
import time
def main():
cmd = 'bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, universal_newlines=True)
for line in p.stdout:
print(f"file_name: {line.strip()}", flush=True)
print(p.poll())
time.sleep(.1)
print(p.poll())
if __name__ == "__main__":
main()
打印:
bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"
file_name: 1
file_name: 2
file_name: 3
file_name: 4
file_name: 5
None
0
要在循环内“让它工作”需要对子进程内发生的事情有特殊的了解。根据上一段代码,我们需要:
#!/usr/bin/env python3
import subprocess
import shlex
import time
def main():
cmd = 'bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, universal_newlines=True)
for line in p.stdout:
# has to be greater than the sleep time in the subprocess to give the subprocess a chance to terminate
print(f"file_name: {line.strip()}", flush=True)
time.sleep(1.1)
print(p.poll())
if __name__ == "__main__":
main()
打印:
bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"
file_name: 1
None
file_name: 2
None
file_name: 3
None
file_name: 4
None
file_name: 5
0
但这不是一个切实可行的解决方案。人们将不得不问进行此轮询的原因是什么?它不提供任何有用的信息,除非您愿意在读取后包含 sleep
调用 ,因为在子进程完成最后一次写入及其终止后总会有一些延迟 ,并且这些 sleep
调用通常是浪费的。您应该一直阅读直到没有更多输出,然后执行 p.wait()
以等待子进程终止,但这是您的选择:
#!/usr/bin/env python3
import subprocess
import shlex
def main():
cmd = 'bash -c "for i in $(seq 1 5);do echo $i; sleep 1; done;"'
print(cmd)
p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, universal_newlines=True)
for line in p.stdout:
print(f"file_name: {line.strip()}", flush=True)
p.wait()
if __name__ == "__main__":
main()