为sys.stdin设置较小的缓冲区大小?

我用下面的bash命令模式运行memcached:

memcached -vv 2>&1 | tee memkeywatch2010098.log 2>&1 | ~/bin/memtracer.py | tee memkeywatchCounts20100908.log 

尝试追踪无与伦比的获取设置密钥平台广泛。

memtracer脚本如下,并按需要工作,只有一个小问题。 看到中间日志文件大小,memtracer.py不会开始获取input,直到memkeywatchYMD.log大小约为15-18K。 有没有更好的方式来读取标准input或者可能的方式来减less缓冲区大小下降到1K以下更快的响应时间?

 #!/usr/bin/python import sys from collections import defaultdict if __name__ == "__main__": keys = defaultdict(int) GET = 1 SET = 2 CLIENT = 1 SERVER = 2 #if < for line in sys.stdin: key = None components = line.strip().split(" ") #newConn = components[0][1:3] direction = CLIENT if components[0].startswith("<") else SERVER #if lastConn != newConn: # lastConn = newConn if direction == CLIENT: command = SET if components[1] == "set" else GET key = components[2] if command == SET: keys[key] -= 1 elif direction == SERVER: command = components[1] if command == "sending": key = components[3] keys[key] += 1 if key != None: print "%s:%s" % ( key, keys[key], ) 

您可以通过使用python的-u标志完全删除标准input/标准输出的缓冲区:

 -u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x) see man page for details on internal buffering relating to '-u' 

手册页澄清:

  -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. 

除此之外,不支持更改现有文件的缓冲,但是可以使用os.fdopen创build一个具有与现有文件相同的基础文件描述符的新文件对象,并可能使用不同的缓冲区。 也就是说,

 import os import sys newin = os.fdopen(sys.stdin.fileno(), 'r', 100) 

应该newin绑定到读取与标准input相同FD的文件对象的名称,但一次只能缓冲大约100个字节(并且可以继续使用sys.stdin = newin来使用新的文件对象作为标准input在那里)。 我说“应该”,因为这个领域在某些平台上曾经有过一些错误和问题(提供跨平台的function相当强大,具有完整的通用性) – 我不确定现在的状态是什么, d绝对推荐在所有感​​兴趣的平台上进行彻底的testing,以确保一切顺利。 ( -u ,完全删除缓冲区,应该在所有平台上使用更less的问题,如果这可能符合您的要求)。

您可以简单地使用sys.stdin.readline()而不是sys.stdin.__iter__()

 import sys while True: line = sys.stdin.readline() if not line: break # EOF sys.stdout.write('> ' + line.upper()) 

这使我在Ubuntu 13.04上使用Python 2.7.4和Python 3.3.1进行行缓冲读取。

sys.stdin.__iter__仍然是行缓冲的,可以通过使用iter双参数forms来创build一个sys.stdin.readline的迭代器,可以有一个大致相同的迭代器(停在EOF,而stdin.__iter__不会) sys.stdin.readline

 import sys for line in iter(sys.stdin.readline, ''): sys.stdout.write('> ' + line.upper()) 

或者提供None作为定点(但请注意,那么您需要自己处理EOF条件)。

这在Python 3.4.3中适用于我:

 import os import sys unbuffered_stdin = os.fdopen(sys.stdin.fileno(), 'rb', buffering=0) 

fdopen()的文档说这只是open()的别名。

open()有一个可选的buffering参数:

缓冲是用于设置缓冲策略的可选整数。 通过0切换缓冲closures(仅在二进制模式下允许),1select行缓冲(只能在文本模式下使用)以及一个大于1的整数,以指示固定大小的块缓冲区的大小(以字节为单位)。

换一种说法:

  • 完全无缓冲的 stdin需要二进制模式并将零作为缓冲区大小。
  • 行缓冲需要文本模式。
  • 任何其他缓冲区大小似乎都可以在二进制文本模式下工作(根据文档)。

我能用python 2.7做的唯一方法是:

 tty.setcbreak(sys.stdin.fileno()) 

来自Python非阻塞控制台input 。 这完全禁用缓冲并抑制回声。

编辑:关于亚历克斯的答案,第一个命题(用-u调用python)在我的情况下是不可能的(见shebang限制 )。

第二个命题(使用较小缓冲区复制fd: os.fdopen(sys.stdin.fileno(), 'r', 100) )在使用0或1的缓冲区时不起作用,因为它是用于交互式input的我需要每个人物都被立即处理。