Java:有效地计算大文件的SHA-256哈希
我需要计算大文件(或其一部分)的SHA-256哈希。我的实现工作正常,但比C 的CryptoPP计算要慢得多(25分钟vs. 30
GB文件的10分钟)。我需要的是在C 和Java中执行时间相似,因此散列几乎可以同时准备好。我也尝试了Bouncy
Castle的实现,但是它给了我相同的结果。这是我如何计算哈希值:
int buff = 16384;try {
RandomAccessFile file = new RandomAccessFile("T:\\someLargeFile.m2v", "r");
long startTime = System.nanoTime();
MessageDigest hashSum = MessageDigest.getInstance("SHA-256");
byte[] buffer = new byte[buff];
byte[] partialHash = null;
long read = 0;
// calculate the hash of the hole file for the test
long offset = file.length();
int unitsize;
while (read < offset) {
unitsize = (int) (((offset - read) >= buff) ? buff : (offset - read));
file.read(buffer, 0, unitsize);
hashSum.update(buffer, 0, unitsize);
read += unitsize;
}
file.close();
partialHash = new byte[hashSum.getDigestLength()];
partialHash = hashSum.digest();
long endTime = System.nanoTime();
System.out.println(endTime - startTime);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
回答:
我的解释可能无法解决您的问题,因为它很大程度上取决于您的实际运行时环境,但是当我在系统上运行您的代码时,吞吐量受磁盘I /
O限制,而不是哈希计算。通过切换到NIO并不能解决问题,而仅仅是由于您以很小的片段(16kB)读取文件的事实而引起的。将系统上的缓冲区大小(buff)增加到1MB而不是16kB会使吞吐量增加一倍以上,但是以>
50MB / s的速度,我仍然受到磁盘速度的限制,无法完全加载单个CPU内核。
顺便说一句:您可以通过将DigestInputStream包裹在FileInputStream周围,通读文件并从DigestInputStream获取计算得出的哈希值,而不是像代码中那样将数据从RandomAccessFile手动改组为MessageDigest,来大大简化实现。
我使用较旧的Java版本进行了一些性能测试,这里的Java 5和Java
6之间似乎存在相关差异。我不确定是否优化了SHA实施,或者VM是否以更快的速度执行代码。我使用不同的Java版本(1MB缓冲区)获得的吞吐量为:
- Sun JDK 1.5.0_15(客户端):28MB / s,受CPU限制
- Sun JDK 1.5.0_15(服务器):45MB / s,受CPU限制
- Sun JDK 1.6.0_16(客户端):42MB / s,受CPU限制
- Sun JDK 1.6.0_16(服务器):52MB / s,受磁盘I / O限制(85-90%CPU负载)
我对CryptoPP
SHA实现中的汇编程序部分的影响有些好奇,因为基准测试结果表明SHA-256算法在Opteron上仅需要15.8个CPU周期/字节。不幸的是,我无法在cygwin上用gcc构建CryptoPP(构建成功,但是生成的exe立即失败),但是在VS2005(默认发行版配置)下建立了性能基准,并在CryptoPP中支持汇编器和不使用汇编器,并与Java
SHA进行了比较。在内存缓冲区中实现,不考虑任何磁盘I / O,我在2.5GHz Phenom上获得以下结果:
- Sun JDK1.6.0_13(服务器):26.2个周期/字节
- CryptoPP(仅C ++):21.8个周期/字节
- CryptoPP(汇编器):13.3周/字节
这两个基准测试都计算一个4GB空字节数组的SHA哈希,以1MB的块对其进行迭代,然后将其传递到MessageDigest#update(Java)或CryptoPP的SHA256.Update函数(C
++)。
我能够在运行Linux的虚拟机中使用gcc 4.4.1(-O3)构建和基准测试CryptoPP。与VS
exe的结果相比,吞吐量提高了一半。我不确定对虚拟机造成的差异有多少,以及由VS通常产生比gcc更好的代码所导致的差异,但是我现在无法从gcc获得任何更准确的结果。
以上是 Java:有效地计算大文件的SHA-256哈希 的全部内容, 来源链接: utcz.com/qa/432099.html