【问题标题】:Run Python script within Python by using `subprocess.Popen` in real time使用 `subprocess.Popen` 在 Python 中实时运行 Python 脚本
【发布时间】:2019-02-26 19:00:43
【问题描述】:

我想从 python 脚本运行 Python 脚本(或任何可执行文件,以这种方式)并实时获取输出。我学习了很多教程,我当前的代码如下所示:

import subprocess
with open("test2", "w") as f:
    f.write("""import time
print('start')
time.sleep(5)
print('done')""")

process = subprocess.Popen(['python3', "test2"], stdout=subprocess.PIPE)
while True:
        output = process.stdout.readline()
        if output == '' and process.poll() is not None:
            break
        if output:
            print(output.strip())
        rc = process.poll()

为清楚起见,第一位只是创建将要运行的文件。

这段代码有两个问题:

  • 它不会实时给出输出。它一直等到该过程完成。

  • 一旦进程完成,它不会终止循环。

非常欢迎任何帮助。

编辑:感谢@JohnAnderson 解决了第一个问题:将if output == '' and process.poll() is not None: 替换为if output == b'' and process.poll() is not None:

【问题讨论】:

  • 如果代码运行不正确,请查看我的最新编辑。
  • 我想你想用output 做别的事?因为否则只需将stdout 设置为None 应该对您有用(默认情况下仍为行缓冲,可能非常取决于平台)。否则,您需要将stdout 附加到一个线程,该线程在传递内容时消耗控制台输出存储和打印内容。
  • @OndrejK。是的,我想稍后在程序中使用output
  • 在 Ubuntu 上,我得到实时输出。你在 Windows 上吗?另外,您需要将if 更改为if output == b'' and process.poll() is not None:,否则它永远不会是True
  • 问题不是你的输入,而是你缓冲的python子进程输出,将-u添加到使用subprocess创建的python调用以关闭缓冲(['python3', '-u', 'test2']),你应该看到线条在“打印”时出现。默认行为是:stdout 到控制台 -> 行缓冲,stdout 到其他任何东西 -> 默认缓冲区(我认为你的情况是 4KB)。

标签: python python-3.x subprocess


【解决方案1】:

昨晚我已经开始使用管道进行此操作:

import os
import subprocess

with open("test2", "w") as f:
    f.write("""import time
print('start')
time.sleep(2)
print('done')""")

(readend, writeend) = os.pipe()

p = subprocess.Popen(['python3', '-u', 'test2'], stdout=writeend, bufsize=0)
still_open = True
output = ""
output_buf = os.read(readend, 1).decode()
while output_buf:
    print(output_buf, end="")
    output += output_buf
    if still_open and p.poll() is not None:
        os.close(writeend)
        still_open = False
    output_buf = os.read(readend, 1).decode()

强制缓冲图片并一次读取一个字符(以确保我们不会阻止来自已填充缓冲区的进程的写入),在进程完成时关闭写入端以确保读取正确捕获 EOF。看过subprocess 之后,结果证明这有点矫枉过正。使用PIPE,您可以免费获得其中的大部分内容,而我以它结束,这似乎工作正常(根据需要调用多次读取以保持清空管道)并假设过程完成,您不必担心关于轮询它和/或确保管道的写入端已关闭以正确检测 EOF 并退出循环:

p = subprocess.Popen(['python3', '-u', 'test2'],
                     stdout=subprocess.PIPE, bufsize=1,
                     universal_newlines=True)
output = ""
output_buf = p.stdout.readline()
while output_buf:
    print(output_buf, end="")
    output += output_buf
    output_buf = p.stdout.readline()

这有点不那么“实时”,因为它基本上是行缓冲的。

注意:我已将 -u 添加到您的 Python 调用中,因为您还需要确保您的被调用进程的缓冲不会妨碍您。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-15
    • 1970-01-01
    • 2011-03-09
    • 2014-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    相关资源
    最近更新 更多