java.util.zip.CRC32和java.util.zip.Adler32的性能对比分析

原文:java.util.zip.CRC32 and java.util.zip.Adler32 performance
作者:Mikhail Vorontsov

校验码是把任意长度的字节内容输入通过特定算法变换为一个长度较短的字节数组(在CRC32和Adler32中变换为整数(Integer))。校验码最主要的一个特点是,即使输入内容发生了很小的变化,输出内容也会有极为明显的差别。校验算法通常在以下两种场景中使用:

  • 当主机已经分别接收到一个完整文件和其对应的校验码时,我们要计算出整个文件的校验码,与接收到的校验码进行对比,来确认文件在传输的过程中没有被篡改。
  • 当主机正在从某个输入流源源不断地读取文件时,校验码的计算是实时的,每次校验操作都只对文件的一部分进行处理。当某些原因导致主机与输入设备的连接断开,主机尝试重新传输时,我们会使用最后一次计算得到的校验码和读取到的文件位置与当前重传的数据内容进行比较,以免对前面已经传输过的数据进行重新处理,从而使得传输可以从当前位置继续进行。

在标准JDK中,最常使用的校验算法是java.util.zip.CRC32。许多开发者认为这是Java唯一的标准校验算法实现(其中也有人会说这是标准的CRC(Cyclic Redundancy Check,循环冗余校验)实现)。实际上,Java中还有另一种校验算法叫java.util.zip.Adler32,这两种算法都实现了同一个接口:java.util.zip.Checksum。

这两种校验算法是有区别的,Adler32比CRC32稍微弱一些,不过如果当需要校验的内容长达几千字节甚至更多时,你可以忽略校验质量上的差异。更重要的是,Adler32的计算速度比CRC32快。下面的列表对这两种校验算法的处理速度进行了比较,处理的内容是一个500MB的存档文件(文件已经预先读取到内存中)

500MB数据容校验速度对比

Adler32,一次性处理CRC32,一次性处理Adler32,每次处理区块大小10 bytesCRC32,每次处理区块大小10 bytesAdler32,每次处理区块大小1000 bytesCRC32,每次处理区块大小1000 bytes
Java 60.233 s1.526 s3.585 s4.119 s0.253 s1.545 s
Java 70.227 s0.666 s3.684 s3.691 s0.267 s0.699 s

如你所见,在Java 6中,当单次处理的区块足够大时,Adler32的速度是CRC32的5~6倍;而在Java 7中明确地对CRC32进行了性能优化,Adler32的速度只比CRC32快了2~3倍。使用小容量的区块进行处理时,JNI调用的成本是影响速度的最大因素。

有人可能觉得0.3s和1.5s的时间差异对于500MB的内容来说没有什么值得关注的地方,这并不完全正确。如今硬盘的读取速度能达到100M/s,读取500MB数据最多只需要5s,在这样的情况下,额外的1秒时间(1.5-0.3 s)就会造成20%的性能下降。换个方式说,你可以理解为“我们的系统使用CRC32能达到500,000条信息/每秒的处理速度,而使用Adler32可以达到600,000条信息/每秒”。

总结

如果你可以自由选择校验算法实现,你可以先尝试使用Adler32。如果它的校验质量对你来说已经足够了的话,使用它比CRC32要更好。无论在什么情况下,你应当使用Checksum接口来访问Adler32/CRC32的逻辑。

在计算校验码时,请至少使用500 bytes的分区大小,否则JNI调用会造成不可忽略的时间消耗。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值