【问题标题】:Avoid buffered reading on "for line in ..."避免对“for line in ...”进行缓冲读取
【发布时间】:2014-07-21 11:00:06
【问题描述】:

我正在从命名管道中逐行读取,该管道以逐秒的节奏提供行。我正在尝试简单的

for line in file:
    processLine(line)

但从未调用过processLine()。 (编辑:在读取了很多行之后,它最终会被调用,这需要几分钟。)使用strace 进行调查表明,该过程确实每秒都在完成一个read() 系统调用,并且正如预期的那样接收一个完整的每次都排队。

我只能猜测for line in 习惯用法会缓冲输入,并且稍后会在每个输入行中调用processLine(),可能是当缓冲区已满或输入终止时(在我的情况下它永远不会) .

我可以将此处使用的缓冲区显式设置为更小吗?

或者是否有另一种方法来调整这件事,以便每一行也以逐秒的节奏处理?

编辑:

目前我正在使用此解决方法:

for line in lineByLine(namedPipe):
    …

这是lineByLine()

def lineByLine(openFile):
    line = ''
    while True:
        char = os.read(openFile.fileno(), 1)
        if not char:
            if line:
                yield line
            break
        line += char
        if line.endswith('\n'):
            yield line
            line = ''

但是这种丑陋的解决方法当然是没有办法的。

【问题讨论】:

  • 不确定,但也许“with”会有所帮助? " with file as f: for line in f: processLine(line)"
  • @Anonymous:我已经在使用那个成语了(并且有问题)。
  • @Alfe 检查python bug report。建议可以使用readline
  • 没错。我发现了同样的建议here ;-)

标签: python file for-loop buffer


【解决方案1】:

正如您在问题中提到的那样,file.next() 内部缓冲。通常这种行为是正确的并且无法检测到。

file.readline() 内部缓冲的方式不同。您笨拙的示例程序创建了一个生成器,它允许将file.readline() 用作for 循环中的可迭代对象。

创建这样一个可迭代的更简单的方法是使用iter 的两个参数形式:

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

【讨论】:

  • 我不愿意接受你的解决方案,因为它没有任何解释,所以如果你补充一两句话,我很乐意接受。 (是的,我知道,解释已经在其他答案中了,所以当你重新表述它时,你可能会觉得抄袭,但如果其他人也有这个问题并找到我的问题,那么接受的答案应该是一个完整的答案。)
【解决方案2】:

我在一些文档(关于-u 选项)中发现文件迭代器的内部缓冲区无法关闭。但是可以在while True: 循环中使用readline() 来进行行缓冲。所以:

def lineByLine(openFile):
    while True:
        line = openFile.readline()
        if not line:
            break
        yield line

现在这对我有用,我认为没有其他方法(更优雅)可以规避这个问题。毕竟这现在是一种解决方案:-/

【讨论】:

    猜你喜欢
    • 2012-10-16
    • 1970-01-01
    • 2019-03-13
    • 2019-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多