TLDR;在python gzip
、bz2
、lzma
等可用的各种压缩算法中,哪种解压性能最好?
全面讨论:
Python 3 有各种用于压缩/解压缩数据的模块,
包括gzip
、bz2
和lzma
. gzip
并且bz2
还可以设置不同的压缩级别。
如果我的目标是平衡文件大小(/压缩比)和解压缩速度(压缩速度不是问题),那么哪个是最佳选择?解压缩速度比文件大小更重要,但由于有问题的未压缩文件每个约为 600-800MB(32 位 RGB .png 图像文件),而且我有十几个,我确实想要一些压缩。
我的用例是我从磁盘加载十几个图像,对它们进行一些处理(作为 numpy 数组),然后在我的程序中使用处理后的数组数据。
- 图像永远不会改变,我只需要在每次运行程序时加载它们。
- 处理所需的时间与加载(几秒钟)大致相同,因此我试图通过保存已处理的数据(使用
pickle
)来节省一些加载时间,而不是每次都加载原始的、未处理的图像。最初的测试很有希望——加载原始/未压缩的腌制数据不到一秒,而加载和处理原始图像需要 3 或 4 秒——但如上所述导致文件大小约为 600-800MB,而原始 png 图像是只有大约 5MB。所以我希望我可以通过以压缩格式存储挑选的数据来在加载时间和文件大小之间取得平衡。
更新:情况实际上比我上面所说的要复杂一些。我的应用程序使用
PySide2
,所以我可以访问这些Qt
库。pillow
如果我读取图像并使用( )转换为 numpy 数组PIL.Image
,我实际上不需要进行任何处理,但将图像读入数组的总时间约为 4 秒。- 相反,如果我
QImage
用来读取图像,那么我必须对结果进行一些处理,以使其可用于我的程序的其余部分,因为QImage
加载数据的方式是字节序的——基本上我必须交换位顺序和然后旋转每个“像素”,使 alpha 通道(显然是由 QImage 添加的)最后而不是第一个。整个过程大约需要 3.8 秒,比仅使用 PIL稍微快一点。 - 如果我保存
numpy
未压缩的数组,那么我可以在 0.8 秒内重新加载它们,这是迄今为止最快的,但文件大小很大。
┌────────────┬────────────────────────┬───────────────┬─────────────┐
│ Python Ver │ Library/Method │ Read/unpack + │ Compression │
│ │ │ Decompress (s)│ Ratio │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.7.2 │ pillow (PIL.Image) │ 4.0 │ ~0.006 │
│ 3.7.2 │ Qt (QImage) │ 3.8 │ ~0.006 │
│ 3.7.2 │ numpy (uncompressed) │ 0.8 │ 1.0 │
│ 3.7.2 │ gzip (compresslevel=9) │ ? │ ? │
│ 3.7.2 │ gzip (compresslevel=?) │ ? │ ? │
│ 3.7.2 │ bz2 (compresslevel=9) │ ? │ ? │
│ 3.7.2 │ bz2 (compresslevel=?) │ ? │ ? │
│ 3.7.2 │ lzma │ ? │ ? │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.7.3 │ ? │ ? │ ? │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.8beta1 │ ? │ ? │ ? │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.8.0final │ ? │ ? │ ? │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.5.7 │ ? │ ? │ ? │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.6.10 │ ? │ ? │ ? │
└────────────┴────────────────────────┴───────────────┴─────────────┘
.png 图像示例:以这张 5.0Mb 的 png 图像为例,它是阿拉斯加海岸线的高分辨率图像。
png/PIL 案例的代码(加载到numpy
数组中):
from PIL import Image
import time
import numpy
start = time.time()
FILE = '/path/to/file/AlaskaCoast.png'
Image.MAX_IMAGE_PIXELS = None
img = Image.open(FILE)
arr = numpy.array(img)
print("Loaded in", time.time()-start)
在我使用 Python 3.7.2 的机器上,这个负载大约需要 4.2 秒。
或者,我可以加载通过选择上面创建的数组生成的未压缩的 pickle 文件。
未压缩的pickle负载情况的代码:
import pickle
import time
start = time.time()
with open('/tmp/test_file.pickle','rb') as picklefile:
arr = pickle.load(picklefile)
print("Loaded in", time.time()-start)
在我的机器上从这个未压缩的 pickle 文件加载大约需要 0.8 秒。