假如想储存一百万t个0,用什么压缩比较好?
实测:用 zstd 比较好,压缩完大约32TB,时间需要约11年。
其实题主的这个问题一点都不无厘头,也并不是很好解决:
1) 程序并不能像人类预先知道答案,然后先验的上帝视角的记录一个100W,T,0,这就是现实中不会有这样的算法:能够一句话表示100万T个0(但你当然可以自定义一个这样的算法,只是不具有通用性);
2) 压缩算法都是有字典的,字典的编写是每滑动固定长度的字节数来压缩的,这个意义上讲,现实中的压缩算法不会是一句话表示100万t的0,而是:n 个 4k 0 或者 n 个8k 0。
有点类似于位图和矢量图的区别,矢量图记录的是两点坐标以及中间的画法(并没有记录像素),所以可以放大很多倍都不模糊,而位图是记录的像素点,是每个像素里面的RGBA值,所以放大就模糊了。视频的像素图每一帧都有差别,虽然人眼觉得是一样的,但计算机其实记录了每帧的区别,区别过多,字典就收益不大了,所以大家用压缩软件压视频多半都是压了个寂寞。以前微软有3个出去的程序员,搞的 rmvb 这种格式,就可以把 rm 格式的视频在人眼分辨不出来的情况下压缩很小,这对于互联网而言价值超高,虽然最后他们仨决定收费把rmvb作死了,但由此可以知道,压缩算法实现起来,针对性优化打表就可以(比如游戏里面很多固定的计算都不实时计算的,因为慢,都是直接打表:100万t个0),而要想通用化,难度就很大,打表就无能为力了。
下面让我们来看看 zip 算法结果 和 zstd 算法结果,先说答案:
50GB个0的文本文件:
zip 压缩结果为: 52.1 MB
zstd 压缩结果为:1.6 MB
那如果把zstd这个1.6MB再zstd压缩一次呢?就只有410字节了,和直接记录一行100万t个0差不太多了,故下面的估算只讨论压缩一次的情况,压缩多次属于优化,不属于讨论本身了, 本文不讨论反复压缩这种情况,感兴趣的同学可以自行实验压缩2、3、4、5……次。我的测试,压缩3次收益最大,100GB 的全0 可以压缩成 246 字节 的zst文件。
下面是实现,供参考,不感兴趣实操的同学,后面的可以不看了:
1)生成50GB个全0的txt:
import os
m1000k = []
# 1MB 个0
for i in range(1024*1024):
m1000k.append('0')
m = ''.join(m1000k)
with open('0.txt','a') as f:
# 50 GB个0
for i in range(1024*50):
f.write(m)
然后:
2)用系统自带的 zip 压缩:
time zip 0_zip.zip 0.txt
# 结果: 52 MB
# 耗时: 3 分 22 秒
real 3m21.612s
user 2m57.004s
sys 0m23.929s
3)用系统自带的 zstd 压缩:
time zstd 0.txt -o 0_zstd.zst -19
# 结果: 1.6 MB
# 耗时: 16 秒
real 0m15.532s
user 0m11.000s
sys 0m7.844s
4) 那么问题来了, 50GB 压到 1.6 MB, 100GB 难道就是 3.2MB,嘿,您别光说不练啊,实测一下啊,嘿,您猜怎么着?还真是!3.3MB
时间也是2倍
real 0m31.569s
user 0m29.574s
sys 0m16.204s
那么我们可以做一个粗略的估算:
100GB个0,zstd 压缩大小为3.2MB,耗时31.5秒,
1,000,000 * 1024 / 100 = 1024万:
约 31.25TB ,耗时 3733 天(约11年)
如果zstd压缩两次,就只有 3.9GB 了,时间会更长一些,此处不展开讨论多次压缩情况。
为了看zstd的压缩是不是随着文件大小的增长而线形增长的,我也做了10GB - 60GB的测试:
10GB:
real 0m3.251s
user 0m2.984s
sys 0m1.729s
20GB:
real 0m6.475s
user 0m5.914s
sys 0m3.306s
30GB:
real 0m9.689s
user 0m8.857s
sys 0m4.925s
40GB:
real 0m12.545s
user 0m11.807s
sys 0m6.458s
60GB:
real 0m18.813s
user 0m17.708s
sys 0m9.694s
注:在不同的硬件上,时间会略有差异,本测试在 M2 MacBook Air 上进行,如果您有刚出的 M4 Mac mini,欢迎您在评论区分享您测试 100 GB 压缩的时间,把上面python 代码中的 1024 x 50 改成 1024 x 100就是100GB了。