3

私は次のような複数のPythonプロセスを実行しています:

find /path/to/logfiles/*.gz | xargs -n1 -P4 python logparser.py

そして、出力は時々スクランブルされます。

出力ストリームはバッファリングされておらず、書き込みのサイズはデフォルトのシステム(osx 10.8.2、python 2.7.2)で定義された512バイトのPIPE_BUFよりも小さいため、書き込みはアトミックである必要があると思いますが、出力がスクランブルされることがあります。私は何かが欠けているに違いありません、そしてどんな提案もいただければ幸いです。

ありがとう。

スクリプトの簡略化されたスケルトンは次のとおりです。

import argparse
import csv
import gzip


class class UnbufferedWriter(object):
    """Unbuffered Writer from 
       http://mail.python.org/pipermail/tutor/2003-November/026645.html

    """

    def __init__(self, stream):
        self.stream = stream

    def write(self, data):
        self.stream.write(data)
        self.stream.flush()

    def __getattr__(self, attr):
        return getattr(self.stream, attr)


def parse_records(infile):
    if infile.name.endswith('.gz'):
        lines = gzip.GzipFile(fileobj=infile)
    else:
        lines = infile

    for line in lines:
        # match lines with regex and filter out on some conditions.
        yield line_as_dict

def main(infile, outfile):
    fields = ['remote_addr', 'time', 'request_time', 'request', 'status']
    writer = csv.DictWriter(outfile, fields, quoting=csv.QUOTE_ALL)

    for record in parse_records(infile):
        row_as_dict = dict(
            remote_addr=record.get('remote_addr', ''),
            time=record.get('time', ''),
            request_time=record.get('request_time', ''),
            request=record.get('request', ''),
            status=record.get('status', '')
        )
        writer.writerow(row_as_dict)

if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
    parser.add_argument('outfile', nargs='?', type=argparse.FileType('w', 0), default=sys.stdout)

    pargs = parser.parse_args()
    pargs.outfile = UnbufferedWriter(pargs.outfile)

    main(pargs.infile, pargs.outfile)
4

1 に答える 1

3

GNUParallelの使用を検討することをお勧めします。デフォルトでは、インスタンスの実行が完了するまで出力はバッファリングされます。

データを出力するジョブを実行する場合、複数のジョブの出力を一緒に実行したくないことがよくあります。GNU parallelは、デフォルトで各ジョブの出力をグループ化するため、ジョブが終了すると出力が出力されます。ジョブの実行中に出力を印刷する場合は、-uを使用できます。

スクリプトを実行する最良の方法はvaiだと思います。

find /path/to/logfiles/*.gz | parallel python logparser.py

また

parallel python logparser.py ::: /path/to/logfiles/*.gz

フラグを使用して実行するプロセスの数を指定できます。-jつまり、-j4

Parallelの良いところは、入力引数のデカルト積をサポートしていることです。たとえば、ファイルごとに繰り返し処理する追加の引数がある場合は、次を使用できます。

parallel python logparser.py ::: /path/to/logfiles/*.gz ::: 1 2 3

これにより、複数のプロセスで以下が実行されます。

python logparser.py /path/to/logfiles/A.gz 1
python logparser.py /path/to/logfiles/A.gz 2
python logparser.py /path/to/logfiles/A.gz 3
python logparser.py /path/to/logfiles/B.gz 1
python logparser.py /path/to/logfiles/B.gz 2
python logparser.py /path/to/logfiles/B.gz 3
...

幸運を!

于 2013-01-16T22:44:03.653 に答える