web-dev-qa-db-ja.com

sys.stdinに小さいバッファサイズを設定しますか?

次のbashコマンドパターンでmemcachedを実行しています。

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

プラットフォーム全体のキーのセットへの比類のない取得を追跡しようとします。

Memtracerスクリプトは以下のとおりであり、1つの小さな問題がありますが、希望どおりに機能します。中間ログファイルのサイズを監視していると、memkeywatchYMD.logのサイズが約15〜18Kになるまで、memtracer.pyは入力の取得を開始しません。 stdinで読み取るより良い方法、または応答時間を短縮するためにバッファサイズを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], )
25
David

Pythonの-uフラグを使用すると、stdin/stdoutからバッファリングを完全に削除できます。

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

そしてmanページは明確にします:

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

shouldnewinを、標準入力と同じFDを読み取るファイルオブジェクトの名前にバインドしますが、バッファリングされるのは約100バイトのみです。時間(そして、sys.stdin = newinを続行して、そこから新しいファイルオブジェクトを標準入力として使用できます)。この領域を使用して、一部のプラットフォームで多くのバグや問題が発生したため、「すべき」と言います(クロスプラットフォームに完全な機能を提供するのはかなり難しい機能です)一般性)-現在の状態はわかりませんが、すべてがスムーズに進むように、対象となるすべてのプラットフォームで徹底的にテストすることを強くお勧めします。 (-u、バッファリングを完全に削除すると、要件を満たす可能性がある場合は、すべてのプラットフォームで問題が少なくなります)。

34
Alex Martelli

sys.stdin.readline()の代わりにsys.stdin.__iter__()を使用するだけです。

import sys

while True:
    line = sys.stdin.readline()
    if not line: break # EOF

    sys.stdout.write('> ' + line.upper())

これにより、Ubuntu13.04でPython 2.7.4およびPython 3.3.1を使用した行バッファー読み取りが可能になります。

22
Søren Løvborg

sys.stdin.__iter__はまだ行バッファリングされているので、 iterの2引数形式 を使用して、ほぼ同じように動作するイテレータ(EOFで停止しますが、stdin.__iter__は停止しません)を使用できます。 sys.stdin.readlineのイテレータを作成します。

import sys

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

または、センチネルとしてNoneを指定します(ただし、EOF条件を自分で処理する必要があることに注意してください)。

11
Antti Haapala

これはPython 3.4.3:

_import os
import sys

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

fdopen() のドキュメントには、open()の単なるエイリアスであると記載されています。

open() にはオプションのbufferingパラメータがあります:

bufferingは、バッファリングポリシーを設定するために使用されるオプションの整数です。 0を渡してバッファリングをオフに切り替え(バイナリモードでのみ許可)、1を渡して行バッファリングを選択し(テキストモードでのみ使用可能)、1より大きい整数を渡して固定サイズのチャンクバッファのサイズをバイト単位で示します。

言い換えると:

  • 完全にバッファリングされていないstdinにはbinaryモードが必要であり、バッファサイズとしてゼロを渡します。
  • Line-bufferingにはtextモードが必要です。
  • その他のバッファサイズは、binaryモードとtextモードの両方で機能するようです(ドキュメントによる)。
3

問題はPythonではなく、コマンドをパイプでチェーンするときにLinuxシェルが注入するバッファリングにある可能性があります。これが問題である場合、入力は行ごとではなく、 4Kブロック。

このバッファリングを停止するには、コマンドチェーンの前にunbufferパッケージのexpectコマンドを付けます(例:

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

パイプラインの途中で使用する場合、unbufferコマンドには-pオプションが必要です。

1
EvertW

python 2.7でそれを行うことができる唯一の方法は:

_tty.setcbreak(sys.stdin.fileno())
_

from Pythonノンブロッキングコンソール入力 。これにより、バッファリングが完全に無効になり、エコーも抑制されます。

編集:アレックスの答えに関して、私の場合、最初の命題(python with _-u_)を呼び出すことはできません( シバン制限 を参照)。

2番目の命題(小さいバッファーでfdを複製する:os.fdopen(sys.stdin.fileno(), 'r', 100))は、0または1のバッファーを使用すると機能しません。これは、対話型入力の場合であり、押されたすべての文字をすぐに処理する必要があるためです。

0
calandoa