Python脚本之间的管道通信

4
我可以为您翻译以下内容,这是一段关于IT技术的翻译,涉及代码操作。为了更好地理解这段翻译,请注意保留HTML标记。

我有一个简单的脚本,从设备中读取值并通过print输出它们。另一个脚本通过监听标准输入并解释每个数字。该设备每秒输出一个数字。令人惊讶的是,在我的Ubuntu计算机上将这两个脚本通过管道连接时却无法正常工作。然而,如果第一个脚本不是从设备读取数据而是尽可能快地生成随机数,则第二个脚本可以成功接收数据。

下面是一个简化版的示例:

print.py:

#!/usr/bin/env python2
import time
import sys

while True:
    time.sleep(1)  # without this everything works
    print "42"
    sys.stdout.flush()

read.py:

#!/usr/bin/env python2
import sys

while True:
    for str in sys.stdin:
        print str

命令行调用:

vorac@laptop:~/test$ ./print.py | ./read.py

这是最终结果。第一段脚本从设备中读取数据,第二段将数据分别在两个不同的时间框架内进行图形化展示(显示的是随机数字)。

输入图片描述


这个可能对你有趣:https://dev59.com/D3A65IYBdhLWcg3wuRF8 - vlp
http://unix.stackexchange.com/questions/25372/turn-off-buffering-in-pipe - Karoly Horvath
我刚刚在 read.py 中添加了 newin = os.fdopen(sys.stdin.fileno(), 'r', 0); sys.stdin = newin,但是没有任何变化。我强烈希望以编程方式解决这个问题,并保持脚本调用的简单性。 - Vorac
1
为什么不在同一个脚本中同时完成两个任务呢? - MKesper
@MKesper,这是一个用于读取、记录和展示温度数据的程序。能够独立使用模块似乎是一个很好的特性 - 你可以只监听设备,或者只绘制一些随机数据,或者在其他数据上运行可中断的记录器。 - Vorac
@Vorac 可以通过将每个模块制作成生成器、单独的函数或其他类似的形式轻松解决。话虽如此,拥有执行小任务的单独程序符合 UNIX 哲学。但在这种情况下,您也可以使用 shell 脚本或标准的 UNIX 工具,例如 cat - David Z
2个回答

3
啊,这是一个棘手的问题。这是因为sys.stdin的迭代方法(即xreadlines())是有缓冲区的。换句话说,当您的循环隐式地调用next(sys.stdin)来获取下一行输入时,Python尝试读取来自真正的底层标准输入流,直到其内部缓冲区已满,只有在缓冲区已满后才会继续执行循环体。缓冲区大小为8千字节,所以这需要一段时间。
您可以通过将sleep()调用中的时间延迟减少到0.001或类似值来查看此内容,具体取决于您系统的能力。如果您恰好时间到位,您会看到几秒钟什么都没有,然后一整块42一起输出。
要解决这个问题,请使用未缓冲的sys.stdin.readline()
while True:
    line = sys.stdin.readline()
    print line

在打印文本之前,您可能还希望去掉末尾的换行符,否则会出现双倍的换行符。使用 line.rstrip('\n'),或者只需使用 print line, 来抑制额外的换行符。


2

我修改了你的read.py文件,现在它可以正常运行:)你忘记从stdin中使用.readline()方法。

import sys
while True:
    line = sys.stdin.readline()
    if line:
        print line.strip()
    else:
        continue

输出结果为:
$ python write.py | python read.py 
42
42
42
42
42
42
42

我认为readLine()很重要,时间是无用的,我在这里检查其他东西...已经更正。 - Amey Jadiye

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接