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

27 投票
6 回答
22863 浏览
提问于 2025-04-16 03:52

我正在使用以下的bash命令来运行memcached:

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

目的是为了追踪在整个平台上,哪些键的获取(get)和设置(set)没有匹配上。

下面是memtracer脚本,它能正常工作,但有一个小问题。观察中间日志文件的大小时,我发现memtracer.py在memkeywatchYMD.log文件的大小达到大约15-18K之前,不会开始接收输入。有没有更好的方法来读取标准输入,或者有没有办法把缓冲区的大小减少到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], )

6 个回答

13

虽然 sys.stdin.__iter__ 仍然是行缓冲的,但我们可以通过使用 iter函数的两参数形式 来创建一个几乎表现相同的迭代器(它会在文件结束时停止,而 stdin.__iter__ 不会)。这个迭代器是基于 sys.stdin.readline 的:

import sys

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

另外,你也可以提供 None 作为结束标志(但要注意,这样的话你需要自己处理文件结束的情况)。

24

你可以直接用 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 时,可以实现逐行读取。

38

你可以通过使用 Python 的 -u 参数,完全去掉标准输入和输出的缓冲。

-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 创建一个新的文件对象,这个新对象可以和已有的文件共享同一个底层文件描述符,并且可以有不同的缓冲设置。也就是说,

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

应该newin 绑定到一个读取标准输入相同文件描述符的文件对象上,但每次只缓冲大约 100 字节(然后你可以继续用 sys.stdin = newin 来将新的文件对象作为标准输入使用)。我说“应该”是因为这个功能在某些平台上曾经有很多bug和问题(要做到跨平台的完整功能其实挺难的)——我不确定现在的情况如何,但我绝对建议在所有相关的平台上进行彻底测试,以确保一切顺利。(-u,完全去掉缓冲,应该在所有平台上都能更少出现问题,如果这能满足你的需求的话)。

撰写回答