【问题标题】:stdin should not wait for "CTRL+D"标准输入不应等待“CTRL+D”
【发布时间】:2014-08-08 10:38:12
【问题描述】:

我得到了一个应该从标准输入读取的简单 python 脚本。 因此,如果我将程序的标准输出重定向到我的 python 脚本的标准输入。

但我的程序记录到 python 脚本的内容只有在记录这些内容的程序被杀死时才会“到达”python 脚本。

但实际上,我希望在程序可用时立即处理程序记录的每一行,而不是在我应该 24/7 实际运行的程序退出时处理。

那么我怎样才能做到这一点呢?如何让标准输入在处理数据之前不等待 CTRL+D 或 EOF?

例子

# accept_stdin.py
import sys
import datetime

for line in sys.stdin:
    print datetime.datetime.now().second, line

# print_data.py
import time

print "1 foo"
time.sleep(3)
print "2 bar"

# bash
python print_data.py | python accept_stdin.py

【问题讨论】:

    标签: python stdin


    【解决方案1】:

    像所有文件对象一样,sys.stdin 迭代器以块的形式读取输入;即使一行输入已准备好,迭代器也会在输出任何内容之前尝试读取块大小或 EOF。您可以使用没有此行为的 readline 方法解决此问题:

    while True:
        line = sys.stdin.readline()
        if not line:
            # End of input
            break
        do_whatever_with(line)
    

    您可以将其与 iter 的 2 参数形式结合使用 for 循环:

    for line in iter(sys.stdin.readline, ''):
        do_whatever_with(line)
    

    我建议在您的代码中留下注释,解释您为什么不使用常规迭代器。

    【讨论】:

    • documentation for file.next() 似乎不支持这个。
    • @chepner: "为了使 for 循环成为循环文件行的最有效方式(一种非常常见的操作),next() 方法使用了一个隐藏的预读缓冲区。”
    • "隐藏的预读缓冲区";这意味着会立即读取一个完整的块,即使这超出了返回完整行的必要性。如果可能,以后对next 的调用将在再次从磁盘读取之前从缓冲区中读取。
    • @chepner:您认为文档中是否有任何部分与我的回答明显矛盾?我的测试似乎支持这种解释,尽管我恐怕只能在 Windows 上测试。如果您阅读Python file object source code,您会发现从文件中读取的C 级调用是fread,其大小与Py_UniversalNewlineFread 内的文件对象缓冲区大小相同;我不认为这会提前停止并返回可用的东西。
    • @chepner:在其他部分有更多信息,尽管可能不是那些寻找文件对象信息的人可能会检查的。例如,-u flag 的文档说使用readline 来解决next 的缓冲问题。
    【解决方案2】:

    这也是您的生产者程序的问题,即您将标准输出通过管道传输到 python 脚本的那个。

    确实,由于该程序只打印而不刷新,因此它打印的数据保存在内部程序缓冲区中用于标准输出,而不是刷新到系统。

    print_data.py 中的print 语句之后添加sys.stdout.flush() 调用。

    退出程序时您会看到数据,因为它会在退出时自动刷新。

    请参阅this问题的解释,

    【讨论】:

    • 请注意,“提供”数据的 python 脚本只是一个示例。实际上,我无法控制“提供”数据的实际程序。
    【解决方案3】:

    正如@user2357112 所说,您需要使用:

    for line in iter(sys.stdin.readline, ''):
    

    之后,您需要使用 -u 标志启动 python 以立即刷新标准输入和标准输出。

    python -u print_data.py | python -u accept_stdin.py
    

    你也可以在shebang中指定flag。

    【讨论】:

    • 等等,我正在尝试,但它似乎不起作用,但是.. 我敢肯定 :) 我会发现这个错误,抱歉
    • 是的,@user2357112 是对的,但您还需要 -u 标志
    • 好吧,这种方法看起来不错,而且确实有效,但是因为我无法控制实际程序,所以我无法使程序的标准输出(在此示例中为 print_data.py)无缓冲导致失败。
    • @mic:如果这意味着提供程序程序没有刷新它的输出,那么你就不走运了。鉴于您所说的限制,我认为您无法采取任何措施使其齐平。
    猜你喜欢
    • 1970-01-01
    • 2017-07-07
    • 2018-12-25
    • 1970-01-01
    • 1970-01-01
    • 2016-07-22
    • 2017-02-15
    • 1970-01-01
    相关资源
    最近更新 更多