似乎 fileinput.input
至少比 zcat
慢两倍,即使设置了缓冲。 问题:我可以做些什么来提高性能,而无需编写一堆代码?我测试它的方法是从 urandom 中获取数据,
"""generate.py"""
import base64
with open('/dev/urandom', 'rb') as f:
for _ in xrange(102400):
print(base64.b64encode(f.read(1024)))
运行它并通过 gzip 管道输出,
> python generate.py | gzip - > test_input.gz
zcat时间
> time zcat test_input.gz > /dev/null
zcat test_input.gz > /dev/null 1.56s user 0.02s system 99% cpu 1.576 total
文件输入时间
> time python -c 'import fileinput; list(fileinput.input(files=["test_input.gz"], openhook=fileinput.hook_compressed))'
python -c 3.13s user 0.16s system 99% cpu 3.293 total
这不仅仅是 fileinput.input()
变慢了,因为当它从 stdin 读取时它很好,
> time zcat test_input.gz | python -c 'import fileinput; list(fileinput.input())'
zcat test_input.gz 1.64s user 0.04s system 96% cpu 1.736 total
python -c 'import fileinput; list(fileinput.input())' 0.39s user 0.17s system 31% cpu 1.800 total
我搞砸了 bufsize=
,但运气不好。
写了很多代码
我在 google 上搜索了一下,认为 gzip
本身很慢,发现如果我做一些手动缓冲就没问题,
"""read_buffered_manual.py"""
import gzip
def input_buffered_manual(filename, buf_size=32 * 1024):
fd = gzip.open(filename)
try:
remaining = ''
while True:
input_ = fd.read(buf_size)
if not input_:
if remaining:
yield remaining
return
lines = input_.split('\n')
lines[0] = remaining + lines[0]
remaining = lines.pop()
for line in lines:
yield line
finally:
fd.close()
for line in input_buffered_manual("test_input.gz"):
print line
这很快,实际上比 zcat 还快,
> time python read_buffered_manual.py > /dev/null
python read_buffered_manual.py > /dev/null 1.40s user 0.04s system 99% cpu 1.461 total
好吧,您可以使用专门的工具:
import gzip
import sys
import shutil
for filename in ["test_input.gz"]:
with gzip.open(filename) as file:
shutil.copyfileobj(file, sys.stdout)
这相当快。
我是一名优秀的程序员,十分优秀!