从Flask视图中流式处理Shell输出有效,但永无止境

n2o*_*n2o 5 python stream flask

我想将几个python3脚本的输出流式传输到我的浏览器。我遵循了来自不同SO答案的一些建议,并几乎解决了它。但是我从stdout读取的for循环在执行脚本后会陷入无限循环。输出正确,一切都很好,但无休止的循环是个问题。输出完成后如何结束流?

@app.route('/stream/<script>')
def execute(script):
    def inner():
        assert re.match(r'^[a-zA-Z._-]+$', script)
        exec_path = "scripts/" + script + ".py"
        cmd = ["python3", "-u", exec_path]  # -u: don't buffer output

        proc = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
        )

        for line in iter(proc.stdout.readline, ''):
            yield highlight(line, BashLexer(), HtmlFormatter())
            # If process is done, break loop
   #         if proc.poll() == 0:
   #             break

    env = Environment(loader=FileSystemLoader('app/templates'))
    tmpl = env.get_template('stream.html')
    return Response(tmpl.generate(result=inner()))
Run Code Online (Sandbox Code Playgroud)

当我轮询子进程以查看其是否完成时,脚本的输出将中断,因为当打印速度太快时,它不会打印整个stdout流。如果sleep(1)在每张打印纸之间添加,则不会出现此问题。

该代码可以工作,但是会陷入无限循环。如果我取消注释这些行,则输出将以某种方式进行缓冲,并且部分内容会丢失。我还尝试在单独的线程中轮询子进程,只需要切换一个类似的标志if not running: break,但这会导致相同的行为,例如上面的未注释代码。

phi*_*hag 5

iter(proc.stdout.readline, '')调用 readline 直到遇到等于''. 但是proc.stdout.readline返回bytes对象,并且''str对象,所以两者永远不会相等!

相反,要么写

for line in iter(proc.stdout.readline, b''):
Run Code Online (Sandbox Code Playgroud)

或者,甚至更好:

for line in proc.stdout:
Run Code Online (Sandbox Code Playgroud)