Python等待直到数据在sys.stdin中

18 投票
9 回答
41449 浏览
提问于 2025-04-16 23:34

我的问题是这样的:

我的Python脚本通过sys.stdin接收数据,但它需要等到sys.stdin上有新数据可用时才能继续。

根据Python的手册,我使用了以下代码,但这导致我的CPU完全被占满。

#!/usr/bin/python -u
import sys
while 1:
     for line in sys.stdin.readlines():
         do something useful

有没有什么好的方法来解决高CPU使用率的问题?

编辑:

你们的所有解决方案都不管用。我给你们说说我的具体问题。

你可以配置apache2守护进程,让它把每一行日志发送到一个程序,而不是写入日志文件。

这看起来像这样:

CustomLog "|/usr/bin/python -u /usr/local/bin/client.py" combined

Apache2希望我的脚本一直运行,等待sys.stdin上的数据,并在有数据时进行解析。

如果我只用一个for循环,脚本会退出,因为在某个时刻sys.stdin上没有数据,apache2就会说“哦,你的脚本意外退出了”。

如果我使用一个while true循环,我的脚本就会占用100%的CPU。

9 个回答

3

使用这个:

#!/usr/bin/python
import sys
for line in sys.stdin.readlines():
    pass # do something useful
4

这个方法实际上运行得非常顺利(也就是说,没有CPU过载的问题)——当你从命令行调用这个脚本时,可以这样做:

tail -f input-file | yourscript.py

显然,这并不是最理想的做法——因为你需要把所有相关的输出写入那个文件中——

但这样做没有太多额外的负担!主要是因为使用了 readline(),我觉得:

while 1:
        line = sys.stdin.readline()

它会在那一行停下来,等待更多的输入。

希望这对某些人有帮助!

22

下面的代码应该可以正常工作。

import sys
for line in sys.stdin:
    # whatever

解释一下:

这段代码会逐行读取输入流中的内容。当输入流还在打开状态,但没有完整的一行数据时,循环会一直等待,直到遇到换行符(这时会返回整行数据)或者输入流被关闭(这时会返回缓冲区中剩下的数据)。

一旦输入流关闭,就不能再往stdin写入或读取数据了。就是这么简单。

你代码让CPU过载的原因是,一旦stdin关闭,之后再尝试读取stdin时会立刻返回,不会执行任何操作。实际上,你的代码相当于下面的样子。

for line in sys.stdin:
    # do something

while 1:
    pass # infinite loop, very CPU intensive

也许你可以分享一下你是怎么往stdin写数据的,这样可能会更有帮助。

补充说明:

在Python中,对于for循环、迭代器和readlines()来说,当遇到EOF(文件结束符)时,流会被认为是关闭的。你可以让Python继续读取更多数据,但不能使用之前的方法。Python的手册建议使用

import sys
while True:
    line = sys.stdin.readline()
    # do something with line

当遇到EOF字符时,readline会返回一个空字符串。如果流仍然打开,下一次调用readline会正常工作。你可以在终端中运行这个命令来测试一下。按下ctrl+D会让终端向stdin写入EOF字符。这会导致这篇文章中的第一个程序终止,但最后一个程序会继续读取数据,直到流真正关闭。最后一个程序不会让你的CPU 100%占用,因为readline会等待有数据可返回,而不是返回空字符串。

我只有在从实际文件中调用readline时才会遇到忙碌循环的问题。但在从stdin读取时,readline会正常阻塞。

撰写回答