【发布时间】:2017-04-18 20:54:03
【问题描述】:
你如何使用 python 以与底层库相当的速度 gzip/gunzip 文件?
tl;dr - Use shutil.copyfileobj(f_in, f_out).
我正在解压缩 *.gz 文件作为更大系列文件处理的一部分,并进行分析以尝试让 python 执行“关闭”内置脚本。就我正在处理的数据量而言,这很重要,而且理解起来似乎很重要。
在 ~500MB 上使用 'gunzip' bash 命令,如下所示:
$time gunzip data.gz -k
real 0m24.805s
一个朴素的 Python 实现如下所示:
with open('data','wb') as out:
with gzip.open('data.gz','rb') as fin:
s = fin.read()
out.write(s)
real 2m11.468s
不要将整个文件读入内存:
with open('data','wb') as out:
with gzip.open('data.gz','rb') as fin:
out.write(fin.read())
real 1m35.285s
检查本地机器缓冲区大小:
>>> import io
>>> print io.DEFAULT_BUFFER_SIZE
8192
使用缓冲:
with open('data','wb', 8192) as out:
with gzip.open('data.gz','rb', 8192) as fin:
out.write(fin.read())
real 1m19.965s
尽可能多地使用缓冲:
with open('data','wb',1024*1024*1024) as out:
with gzip.open('data.gz','rb', 1024*1024*1024) as fin:
out.write(fin.read())
real 0m50.427s
很明显它是缓冲/IO 绑定的。
我有一个中等复杂的版本,运行时间为 36 秒,但涉及一个预先分配的缓冲区和紧密的内部循环。我希望有一个“更好的方法”。
上面的代码是合理且清晰的,尽管仍然比 bash 脚本慢。但是如果有一个非常迂回或复杂的解决方案,它不适合我的需要。我的主要警告是我希望看到一个“pythonic”的答案。
当然,总是有这样的解决方案:
subprocess.call(["gunzip","-k", "data.gz"])
real 0m24.332s
但就这个问题而言,是否有更快的“pythonically”处理文件的方法。
【问题讨论】:
-
有时 python 并不总是答案,这有什么问题?
-
您的示例确实没有任何意义:所有三个 python 示例 1) 只是复制并且根本不解压缩 2) 一次将文件全部读入内存 3) 没有方式受 io-buffering 限制。此外,
gunzip和 cpython 的gzip模块使用相同的底层库来完成所有工作 -
感谢您收看这些内容。为必要的编辑道歉。我过早地点击提交。 1) 错过了我的工作代码中的 gzip 前缀。现在添加。 2/3) 通过缓冲它提高了 2 倍的速度。 4)是的,它确实使用了底层库,所以我试图理解它为什么这么慢,特别是考虑到子进程版本与底层库一样快。 4b) foo.gz 是从样本中剪切和粘贴的,现在已修复。 5.) 8219 是一个错字。应该是 8192,对应系统的缓冲区大小,加上小幅提速。
-
这不可能是您正在运行的代码。
as in:是无效的 Python 语法,因为in是关键字,因此不能用作变量名。请不要伪造成绩单。 -
“不要将整个文件读入内存” 版本确实会将整个文件读入内存。它与 "naive python implementation" 完全相同(除了创建该变量)。
标签: python optimization io gzip gunzip