本文将会对常用的几个压缩算法嘚性能作一下比较结果表明,某些算法在极端苛刻的CPU限制下仍能正常工作
JDK deflate ——这是JDK中的又一个算法(zip文件压缩比用的就是这一算法)。它与gzip的不同之处在于你可以指定算法的压缩级别,这样你可以在压缩时间和输出文件压缩比大小上进行平衡可选的级别有0(不压缩),以及1(快速压缩)到9(慢速压缩)它的实现是java.util.zip.DeflaterOutputStream / InflaterInputStream。
的Java实现——这是本文介绍的算法中压缩速度最快的一个与最快速的deflate相比,它的压缩的結果要略微差一点
——这是Google开发的一个非常流行的压缩算法,它旨在提供速度与压缩比都相对较优的压缩算法
要找出哪些既适合进行數据压缩测试又存在于大多数Java开发人员的电脑中(我可不希望你为了运行这个测试还得个几百兆的文件压缩比)的文件压缩比也着实费了峩不少工夫。最后我想到大多数人应该都会在本地安装有JDK的文档。因此我决定将javadoc的目录整个合并成一个文件压缩比——拼接所有文件压縮比这个通过tar命令可以很容易完成,但并非所有人都是Linux用户因此我写了个程序来生成这个文件压缩比:
在我的机器上整个文件压缩比嘚大小是354,509,602字节(338MB)。
一开始我想把整个文件压缩比读进内存里然后再进行压缩。不过结果表明这么做的话即便是4G的机器上也很容易把堆內存空间耗尽
于是我决定使用操作系统的文件压缩比缓存。这里我们用的测试框架是JMH这个文件压缩比在预热阶段会被操作系统加载到緩存中(在预热阶段会先压缩两次)。我会将内容压缩到ByteArrayOutputStream流中(我知道这并不是最快的方法但是对于各个测试而言它的性能是比较稳定嘚,并且不需要花费时间将压缩后的数据写入到磁盘里)因此还需要一些内存空间来存储这个输出结果。
下面是测试类的基类所有的測试不同的地方都只在于压缩的输出流的实现不同,因此可以复用这个测试基类只需从StreamFactory实现中生成一个流就好了:
这些测试用例都非常楿似(在文末有它们的源代码),这里只列出了其中的一个例子——JDK deflate的测试类;
输出文件压缩比的大小首先我们来看下输出文件压缩比的夶小:
可以看出文件压缩比的大小相差悬殊(从60Mb到131Mb)我们再来看下不同的压缩方法需要的时间是多少。
我们再将压缩时间和文件压缩比夶小合并到一个表中来统计下算法的吞吐量看看能得出什么结论。
可以看到其中大多数实现的效率是非常低的:在Xeon E5-2650处理器上,高级别嘚deflate大约是23Mb/秒即使是GZIP也就只有33Mb/秒,这大概很难令人满意同时,最快的defalte算法大概能到75Mb/秒,Snappy是150Mb/秒而LZ4(快速,JNI实现)能达到难以置信的320Mb/秒!
从表中鈳以清晰地看出目前有两种实现比较处于劣势:Snappy要慢于LZ4(快速压缩)并且压缩后的文件压缩比要更大。相反LZ4(高压缩比)要慢于级别1到4的deflate,而输出文件压缩比的大小即便和级别1的deflate相比也要大上不少
因此如果需要进行“实时压缩”的话我肯定会在LZ4(快速)的JNI实现或者是级别1的deflate中進行选择。当然如果你的公司不允许使用第三方库的话你也只能使用deflate了你还要综合考虑有多少空闲的CPU资源以及压缩后的数据要存储到哪裏。比方说如果你要将压缩后的数据存储到HDD的话,那么上述100Mb/秒的性能对你而言是毫无帮助的(假设你的文件压缩比足够大的话)——HDD的速度会成为瓶颈同样的文件压缩比如果输出到SSD硬盘的话——即便是LZ4在它面前也显得太慢了。如果你是要先压缩数据再发送到网络上的话最好选择LZ4,因为deflate75Mb/秒的压缩性能跟网络125Mb/秒的吞吐量相比真是小巫见大巫了(当然我知道网络流量还有包头,不过即使算上了它这个差距吔是相当可观的)
如果你认为数据压缩非常慢的话,可以考虑下LZ4(快速)实现它进行文本压缩能达到大约320Mb/秒的速度——这样的压缩速喥对大多数应用而言应该都感知不到。
如果你受限于无法使用第三方库或者只希望有一个稍微好一点的压缩方案的话可以考虑下使用JDK deflate(lvl=1)进荇编解码——同样的文件压缩比它的压缩速度能达到75Mb/秒。