从子进程读取的实时标准输出仅在从 PyCharm 而不是终端运行时才有效
Posted
技术标签:
【中文标题】从子进程读取的实时标准输出仅在从 PyCharm 而不是终端运行时才有效【英文标题】:Real-time stdout read from subprocess works only when running from PyCharm and not Terminal 【发布时间】:2017-09-24 01:20:25 【问题描述】:应用程序的作用:运行子进程并将标准输出实时显示到 Tkinter 文本框小部件。
当我从 PyCharm 运行应用程序时,这非常有效。
当我从终端 ./application.py
运行应用程序时,它不会实时显示,而是会在进程完成后全部显示。
一些细节:
我有一个子进程正在运行(子进程每 1 秒打印出“SPAM”,持续 10 秒):
process = subprocess.Popen(<some file path>, stdout=subprocess.PIPE, universal_newlines=True)
我正在将标准输出打印到 Tkinter 文本框小部件:
for stdout_line in iter(process.stdout.readline, ""):
self.app.pm_textbox.see(tk.END)
self.app.pm_textbox.insert(tk.INSERT, stdout_line)
所以我的问题是什么可能导致从终端和 PyCharm 运行以不同方式显示标准输出数据?
【问题讨论】:
它继承了当前的stdin
和stderr
。可能在 PyCharm 中这些是管道。不过,我不确定。我认为 PyCharm 对调试有很大的帮助,我没有安装它来测试它的作用。从交互式 shell 运行时,stdin
和 stderr
应该用于终端。尝试将它们覆盖为subprocess.DEVNULL
,这样它们在两种情况下都是相同的。
@eryksun 很遗憾,这并没有解决问题。
您是在 Linux 或其他具有 stdbuf
命令的类 Unix 操作系统上开发吗?如果是这样,请尝试将命令更改为 ['stdbuf', '-oL', filepath]
以覆盖默认行缓冲。如果可行,我想知道 PyCharm 在做什么。
@eryksun 我正在 Ubuntu 16.04 上开发。添加此命令似乎没有改变任何东西 - PyCharm 仍在工作,从终端启动应用程序没有。
这里的症状看起来像是在将输出写入管道之前完全缓冲了输出。典型的缓冲区大小是 4 KiB 或 8 KiB,所以如果你没有那么多数据,缓冲区只会在程序退出时刷新到管道。 stdbuf
并不总是有效。它只会改变默认行为,但有些程序会覆盖它。
【参考方案1】:
我知道这是一个旧线程,但仍然 -
我遇到了和你一样的问题。我问了一个question,这似乎有助于我在处理实时输出方面找到正确的方向。我的问题是我需要区分由 CR 产生的输出并在我的程序中模拟该行为。但后来我也遇到了你的问题——我工作了 3 天,试图找到一个解决方案来解决为什么会发生这种情况。
在阅读了this 并且对他们在那里所做的事情没有运气之后,我发现这个帖子没有答案,但一个comment 经过一些修改后终于帮助了我。
最后对我有用的是:
# This seems to handle This seems to handle
# the terminal output the PyCharm output
proc = subprocess.Popen(["stdbuf", "-oL"] + cmd, stdout=subprocess.PIPE)
out = io.open(proc.stdout.fileno(), mode='r', encoding="utf-8", newline='')
should_cr = False
for line in out:
if should_cr is True:
sys.stdout.write("\r")
sys.stdout.flush()
if line.endswith(os.linesep):
should_cr = False
sys.stdout.write(line)
sys.stdout.flush()
elif line.endswith("\r"):
should_cr = True
line = line.rstrip()
sys.stdout.write(line)
sys.stdout.flush()
如果你不考虑 CR 输出,那当然更简单:
# This seems to handle This seems to handle
# the terminal output the PyCharm output
proc = subprocess.Popen(["stdbuf", "-oL"] + cmd, stdout=subprocess.PIPE)
for line in iter(proc.stdout.readline, ''):
print(line)
请注意,这在 Python 2.7 中适用于我
【讨论】:
以上是关于从子进程读取的实时标准输出仅在从 PyCharm 而不是终端运行时才有效的主要内容,如果未能解决你的问题,请参考以下文章
Jupyter notebook 中 Python 子进程的实时标准输出输出
如何在 node.js 子进程模块中将消息和标准输出从子进程传递给父进程?