当前位置: 首页 > 面试题库 >

Python解压缩的相对性能?

阎伟志
2023-03-14
问题内容

TLDR;的python中提供的各种压缩算法
gzipbz2lzma,等,具有最佳 的减压 性能?

完整讨论:

蟒3具有用于压缩/解压缩的数据的各种模块
,包括gzipbz2lzmagzipbz2可以设置不同的压缩级别。

如果我的目标是平衡文件大小(/压缩比)和解压缩速度(与压缩速度无关),那将是最佳选择?
解压缩速度比文件大小更重要,但是由于有问题的未压缩文件每个约为600-800MB(32位RGB .png图像文件),因此我有十几个文件,因此我确实希望进行
一些 压缩。

  • 我的用例是,我要从磁盘加载一堆图像,对其进行一些处理(作为numpy数组),然后在程序中使用经过处理的数组数据。

    • 映像永远不会改变,我只需要在每次运行程序时加载它们。
    • 处理所需的时间与加载时间(几秒钟)大致相同,因此我试图通过保存处理后的数据(使用pickle)来节省一些加载时间,而不是每次都加载未经处理的原始图像。最初的测试很有希望-加载原始/未压缩的腌制数据花费了不到一秒钟的时间,而加载和处理原始图像则花费了3到4秒钟-但如上所述,文件大小约为600-800MB,而原始png图像仅约5MB。因此,我希望可以通过以压缩格式存储选择的数据来在加载时间和文件大小之间取得平衡。
    • 更新:这种情况实际上比我上面表示的要复杂。我的应用程序使用PySide2,因此我可以访问这些Qt库。

    • 如果我读取图像并使用pillowPIL.Image)转换为numpy数组,则实际上无需进行任何处理,但是将图像读取到数组中的总时间约为4秒。

    • 如果取而代之的是我QImage用来读取图像,则必须对结果进行一些处理,以使其在程序的其余部分中可用,这归因于QImage数据加载方式的字节顺序-基本上,我必须交换位顺序并然后旋转每个“像素”,以使alpha通道(显然是QImage添加的)排在最后而不是排在第一位。这整个过程只需约3.8秒,所以 稍微 比只使用PIL更快。
    • 如果我保存numpy未压缩的数组,则可以在.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 s。

或者,我可以加载通过选择上面创建的数组而生成的未压缩的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)

从此未压缩的泡菜文件加载到我的机器上大约需要0.8s。


问题答案:

您可以使用Python-blosc

它非常快,对于小型阵列(<2GB)也很容易使用。对于像您的示例这样的易于压缩的数据,通常可以更快地压缩数据以进行IO操作。(SATA-SSD:大约500
MB / s,PCIe-SSD:最高3500MB / s)在解压缩步骤中,阵列分配是最昂贵的部分。如果图像的形状相似,则可以避免重复分配内存。

对于以下示例,假定使用连续数组。

import blosc
import pickle

def compress(arr,Path):
    #c = blosc.compress_ptr(arr.__array_interface__['data'][0], arr.size, arr.dtype.itemsize, clevel=3,cname='lz4',shuffle=blosc.SHUFFLE)
    c = blosc.compress_ptr(arr.__array_interface__['data'][0], arr.size, arr.dtype.itemsize, clevel=3,cname='zstd',shuffle=blosc.SHUFFLE)
    f=open(Path,"wb")
    pickle.dump((arr.shape, arr.dtype),f)
    f.write(c)
    f.close()
    return c,arr.shape, arr.dtype

def decompress(Path):
    f=open(Path,"rb")
    shape,dtype=pickle.load(f)
    c=f.read()
    #array allocation takes most of the time
    arr=np.empty(shape,dtype)
    blosc.decompress_ptr(c, arr.__array_interface__['data'][0])
    return arr

#Pass a preallocated array if you have many similar images
def decompress_pre(Path,arr):
    f=open(Path,"rb")
    shape,dtype=pickle.load(f)
    c=f.read()
    #array allocation takes most of the time
    blosc.decompress_ptr(c, arr.__array_interface__['data'][0])
    return arr

基准测试

#blosc.SHUFFLE, cname='zstd' -> 4728KB,  
%timeit compress(arr,"Test.dat")
1.03 s ± 12.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
#611 MB/s
%timeit decompress("Test.dat")
146 ms ± 481 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
#4310 MB/s
%timeit decompress_pre("Test.dat",arr)
50.9 ms ± 438 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
#12362 MB/s

#blosc.SHUFFLE, cname='lz4' -> 9118KB, 
%timeit compress(arr,"Test.dat")
32.1 ms ± 437 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
#19602 MB/s
%timeit decompress("Test.dat")
146 ms ± 332 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
#4310 MB/s
%timeit decompress_pre("Test.dat",arr)
53.6 ms ± 82.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
#11740 MB/s

时机



 类似资料:
  • 使用的字符串: string='hello'+'\r\n'+'world' Java中的预期输出: out.getValue() f.write(Base64.b64Encode(Out.getValue())) F.Close() ByteArrayInputStream(压缩)); InputStreamReader(gis,“UTF-8”));

  • tar [-]c|x|u|r|t[z|j][v] -f 归档文件 [待打包文件] 将多个文件打包为一个归档文件,可以在打包的同时进行压缩。支持的格式为 tar(归档)、gz(压缩)、bz2(压缩率更高,比较耗时) 操作选项 -c 创建 -x 解包 -u 更新 -r 添加 -t 查看 -d 比较压缩包内文件和文件 -A 将 tar 文件添加到归档文件中 格式选项 -z 使用 gz 压缩格式 -j 使

  • 问题内容: 如前所述在这里,你可以使用星拆包未知数量的变量(如函数),但只在Python 3: 在python 2.7中,我能想到的最好的是(不可怕,但很烦人): 有没有办法从__future__之类的分区中导入它,还是我需要自己的函数在python 2.7中进行未知长度的解包? 问题答案: 在python 2.X中,您可以执行以下操作: 只要至少有一个成员,将工作,因为如果只有1个东西它是。 您

  • 本文向大家介绍详解Python 解压缩文件,包括了详解Python 解压缩文件的使用技巧和注意事项,需要的朋友参考一下 zipfile模块及相关方法介绍: 1 压缩 1.1 创建zipfile对象 zipfile.ZipFile(file, mode='r', compression=0, allowZip64=True, compresslevel=None) 创建Zipfile对象,主要参数:

  • 问题内容: 情况如下: 我从Amazon S3获取gzip压缩的xml文档 我以文件形式阅读它们 题 如何直接解压缩流并读取内容? 我不想创建临时文件,它们看起来不太好。 问题答案: 是的,您可以使用该模块解压缩字节流: 到标头的32个偏移量表示gzip标头是预期的但已跳过。 S3键对象是一个迭代器,因此您可以执行以下操作:

  • 问题内容: 我有一个内存和磁盘受限的环境,我需要解压缩以字符串为基础的块(通过xmlrpc二进制传输)发送给我的gzip文件的内容。但是,使用zlib.decompress()或zlib.decompressobj()/ decompress()都可以在gzip标头上使用barf。我已经尝试过偏移gzip标头(在此处记录),但是仍然没有避免使用barf。gzip库本身似乎仅支持从文件解压缩。 以下