【问题标题】:Is there any way to make fileinput.input() with openhook=hook_compressed performant?有什么方法可以使 openhook=hook_compressed 的 fileinput.input() 表现出色吗?
【发布时间】:2014-09-23 01:39:11
【问题描述】:

似乎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() 速度慢,因为它从标准输入读取时没问题,

> 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

【问题讨论】:

    标签: python performance file-io gzip


    【解决方案1】:

    嗯,你可以使用专门的工具:

    import gzip
    import sys
    import shutil
    
    for filename in ["test_input.gz"]:
        with gzip.open(filename) as file:
            shutil.copyfileobj(file, sys.stdout)
    

    这很快。

    【讨论】:

    • 谢谢,但我有点想使用类似 fileinput ... fileinput 是一个方便的模块,用于逐行处理命令行上指定的数据。
    猜你喜欢
    • 1970-01-01
    • 2023-01-05
    • 2023-03-23
    • 1970-01-01
    • 2015-06-25
    • 2014-09-08
    • 2016-03-28
    • 2012-10-31
    • 2021-09-17
    相关资源
    最近更新 更多