假如想储存一百万t个0,用什么压缩比较好?

发布时间:
2024-12-30 14:54
阅读量:
6

实测:用 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了。

END