添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
愤怒的苹果  ·  C 预处理器 | 菜鸟教程·  1 年前    · 
不羁的松树  ·  已解决No converter for ...·  1 年前    · 
狂野的炒饭  ·  Trimmed Mean PCE ...·  1 年前    · 

使用 Python 对数据进行压缩

之前在工作中遇到一个需求,需要在手机小程序端获取到微信小商店店铺的所有商品数据。由于当时我们没有在后台维护用户的商品数据,选择的解决方案是现场调用商品列表接口,然后缓存在 Redis 里。
鉴于 Redis 的内存还是比较宝贵的,而用户的商品数据(转化为 json 格式后)又是一些比较有规律的文本数据,比较适合进行数据压缩,于是我调研了一下 Python 中的数据压缩的方案。

zip 标准库

Python 中有一个标准库 zip ,常用来处理 zip 格式文件,提供的函数和方法也更适合文件操作。在这个案例中我们的数据是通过 http 接口获取的,额外进行一些文件操作有些麻烦和多余, zip 标准库并不适合这个场景。

zlib 标准库

zlib 是一个常用的压缩、解压库,使用了 deflate 算法。 zip unzip 工具背后其实用的就是 zlib 。Python 内置了 zlib 标准库,提供的接口也很简洁易用( zlib.compress zlib.decompress )。

1
2
3
4
5
import zlib
raw = b'abc' * 100
compressed = zlib.compress(raw)
print(f'compress ratio = {len(compressed)/len(raw):.2}') # compress ratio = 0.05
assert zlib.decompress(compressed) == raw

zlib 可以显著压缩数据规模。当然这个例子比较极端,重复了一百遍’abc’,能达到 5%的压缩率。在真实场景下, zlib 大概能将原始数据压缩到 40%到 50%的大小。
zlib-base

zlib.compress 函数的第二个参数 level 表示压缩级别,范围从 0 到 9,数值越低表示压缩速度越快但压缩率也越高(0 表示只编码而不进行压缩),默认值是-1,在 Python 中一般会使用级别 6。我们可以对比一下不同级别的速度和压缩率。
zlib-ratio
zlib-speed
可以看到,在压缩《西游记》小说原文的场景中,级别 1 和级别 9 的压缩率从 50%提高到了 44%,但级别 1 的耗时只有级别 9 的 20%。在数据大小敏感的场景下下,1%的压缩率的提高也是很可观的。
我遇到的这个场景数据是要存在 Redis 里的,并且每个店铺的数据规模有限,倾向于使用更高的压缩率的方案。

lzma 标准库

Python 标准库中的 lzma (顾名思义,使用 lzma 算法)同样可以用于数据压缩,并且有着更高的压缩率,提供的接口与 zlib 也很相似。
lzma
使用 lzma 可以达到三分之一的压缩率,比级别最高的 zlib 压缩率还要高十多个百分点,相对应的,压缩速度和解压速度会慢很多。
lzma-speed
zlib-decompress
Snipaste_2021-05-04_16-28-41.png
在实验中, 使用 lzma 压缩和解压《西游记》的原文的时间是使用级别 9 zlib 的四倍多。

考虑到微信小商店每个店铺的商品不会很多,花在压缩上的 CPU 时间并不长,还要考虑到请求商品列表接口的耗时,我最后在这个业务中选用了 lzma 标准库。

zstd

zlib lzma 都是 Python 标准库,可以开箱即用。Pypi 上还是有一些其他的数据压缩、解压的库,在这里介绍一下 zstd

zstd (Zstandard)是 Facebook 推出的一个压缩算法,提供 zlib 级别的实时压缩速率和更高的压缩比。标准的 zstd 实现是官方的 C lib,在 Pypi 上也有同名的 Python 绑定实现。
zstd zstd 有 22 个级别,选用压缩率最高的级别压缩效果和 lzma 不相上下,压缩速度会快上一些(一般情况下不会用这么高的级别,压缩速度会快很多),但解压速度比 lzma 要快十倍。
在我遇到的这个场景下,解压的数据量不会太大,这一点解压速度的提升还不值得引入一个第三方库。当然遇到更合适的场景的话, zstd 库还是大有所为的。

总结

作为一个自带电池的语言,了解并活用 Python 标准库还是会很大程度上提高开发效率的。