26

次の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], )
4

6 に答える 6

37

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

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

于 2010-09-08T17:40:36.983 に答える
23

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でPython2.7.4およびPython3.3.1を使用した行バッファー読み取りが可能になります。

于 2013-08-14T15:03:34.140 に答える
12

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

import sys

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

またはNone、番兵として提供します(ただし、EOF条件を自分で処理する必要があることに注意してください)。

于 2015-03-07T20:50:14.323 に答える
4

これはPython3.4.3で私のために働きました:

import os
import sys

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

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

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

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

言い換えると:

  • 完全にバッファリングされていないstdinには、バイナリモードが必要であり、バッファサイズとしてゼロを渡す必要があります。
  • 行バッファリングにはテキストモードが必要です。
  • 他のバッファサイズは、バイナリモードとテキストモードの両方で機能するようです(ドキュメントによると)。
于 2015-12-06T22:52:13.763 に答える
2

問題は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をパイプラインの途中で使用する場合は、オプションが必要です。

于 2019-09-18T10:26:32.617 に答える
0

私がPython2.7でそれを行うことができる唯一の方法は:

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

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

編集:アレックスの答えに関して-u、私の場合、最初の命題(でpythonを呼び出す)は不可能です(シバンの制限を参照)。

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

于 2017-02-03T16:45:45.247 に答える