为什么带有无缓冲输出的python进程使用xargs--max procs进行置乱?

为什么带有无缓冲输出的python进程使用xargs--max procs进行置乱?,python,pipe,stdout,buffered,Python,Pipe,Stdout,Buffered,我正在执行多个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 g

我正在执行多个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)

<>你可能想考虑使用。默认情况下,将缓冲输出,直到实例完成运行:

在运行输出数据的作业时,通常不希望输出 要一起运行的多个作业的列表。GNU并行默认为分组 每个作业的输出,因此当作业 完成。如果希望在作业运行时打印输出 运行你可以使用-u

我认为运行脚本的最佳方式是vai:

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

您可以使用
-j
标志指定要运行的进程数,即
-j4

并行的好处在于它支持输入参数的笛卡尔积。例如,如果要对每个文件迭代使用一些附加参数,则可以使用:

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

祝你好运

当您串行运行它(没有-P4)时,是否仍然会得到加扰输出?通过加扰,您的意思是它是正确的输出,只是混淆了还是完全是胡说八道?不,当连续运行时,它是正确的。我所说的加扰是指在行尾或多行的一部分合并到一行之前,很少有行(约25%)被截断。我想重点关注我可能做错了什么,而不是更改工具。此外,默认情况下,OSX上不安装parallel,SL6机箱上也不安装parallel,这将在生产中运行。当使用执行类似功能的perl脚本时,使用--max procs标志是有效的。但这就是您所做的错误。您没有缓冲您的输出,这意味着它被混合写入终端,因为进程以不确定的顺序写入终端(因为它们并行运行)。您没有做错任何事情。xargs有一个导致混合输出的竞争条件,很幸运您的perl脚本没有受到这种情况的影响。请参阅上的竞赛条件和受其影响的perl脚本。如果允许您运行perl脚本,那么您也可以运行GNU并行,因为这是一个perl脚本。请参阅中的“最小安装”:好的,我将尝试合并并行,但我有点困惑。写入是原子的,那么xargs竞争条件是什么,它对标准输出做了什么?此外,以下操作似乎也能起作用:
find/path/to/logfiles/*.gz | xargs-n1-P4 python logparser.py | cat
。那么,为什么要向管道写入数据,而不是向终端写入数据呢?终端和管道缓冲区不同。要查看xargs竞赛条件,请在以下位置运行(第2个)示例:
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
...