Python的快速管道传输

5

我有两个文件,第一个是fizz

#!/usr/bin/python                                                         
import time

print 'started'
time.sleep(3)
print 'ended'

下一个是bar。
#!/usr/bin/python                                                         
import sys

for line in sys.stdin:
    print line

当我运行命令./fizz | ./bar时,我期望它会先打印started,然后等待3秒钟并打印ended,但实际发生的是在3秒钟后同时打印startedended。是否有方法可以获得我想要的行为?谢谢
3个回答

6
现在问题已经明确是在接收方,我提供了一个我喜欢使用的替代方案:
#!/usr/bin/python                                                   
import sys 
import os

for line in iter(sys.stdin.readline, ''):
    sys.stdout.write(line) # \n included in line

iter(func, sentinel) 函数在每次迭代时调用 func(),当函数返回结果等于 sentinel 时结束迭代。


5

好问题。这比应该做的更难一些。

问题确实出现在bar中,具体来说是因为sys.stdin被缓冲了。我尝试使用较小的缓冲区大小打开sys.stdin并使用python -u,但那没起作用。manpage上有这样一句话:

   -u     Force  stdin,  stdout  and  stderr to be totally unbuffered.  On
          systems where it matters, also put stdin, stdout and  stderr  in
          binary  mode.   Note  that there is internal buffering in xread‐
          lines(), readlines() and file-object  iterators  ("for  line  in
          sys.stdin")  which  is  not  influenced by this option.  To work
          around this, you will want to use "sys.stdin.readline()"  inside
          a "while 1:" loop.
最终,以下是对我有效的方法:

最后实现了这个目标:

#!/usr/bin/python                                                   
import sys 
import os

while True:
    line = sys.stdin.readline()
    if not line:
        break
    sys.stdout.write(line) # or print, doesn't matter.

1

有两个问题:

  1. print "something"./foo 中如果被重定向(例如到管道),它不会刷新stdout缓冲区,即当 stdout没有连接到类似tty的设备 比如交互式控制台时
  2. for line in sys.stdin: 可能会一次尝试读取多行

您可以按以下方式修复它:

$ PYTHONUNBUFFERED=1 ./foo | ./bar

./bar 中:

#!/usr/bin/python
import sys

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

即使使用-u选项使./foo的标准输出不带缓冲,并按@Eduardo Ivanec's answer中建议的逐行读取./bar中的输入。

作为替代方案,您可以在./foo中调用sys.stdout.flush()而不是像@kev's answer中建议的那样使其标准输出不带缓冲。


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