为什么带有无缓冲输出的python进程使用xargs--max procs进行置乱?
我正在执行多个python进程,如:为什么带有无缓冲输出的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
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
...