gpt4 book ai didi

Java:高效计算大文件的SHA-256哈希值

转载 作者:搜寻专家 更新时间:2023-10-30 19:48:51 66 4
gpt4 key购买 nike

我需要计算一个大文件(或其中的一部分)的 SHA-256 哈希值。我的实现工作正常,但它比 C++ 的 CryptoPP 计算慢得多(25 分钟对 ~30GB 文件的 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 实现中的影响有点好奇,因为 benchmarks results表明 SHA-256 算法在 Opteron 上只需要 15.8 个 CPU 周期/字节。不幸的是,我无法在 cygwin 上使用 gcc 构建 CryptoPP(构建成功,但生成的 exe 立即失败),但是在 CryptoPP 中使用和不使用汇编器支持的情况下使用 VS2005(默认发布配置)构建性能基准并与 Java SHA 进行比较在内存缓冲区上实现,省略任何磁盘 I/O,我在 2.5GHz Phenom 上得到以下结果:

  • Sun JDK1.6.0_13(服务器):26.2 周期/字节
  • CryptoPP(仅限 C++):21.8 周期/字节
  • CryptoPP(汇编器):13.3 周期/字节

这两个基准计算 4GB 空字节数组的 SHA 散列,以 1MB 的 block 对其进行迭代,将其传递给 MessageDigest#update (Java) 或 CryptoPP 的 SHA256.Update 函数 (C++)。

我能够在运行 Linux 的虚拟机中使用 gcc 4.4.1 (-O3) 构建 CryptoPP 并对其进行基准测试,但只获得了 appr。与 VS exe 的结果相比,吞吐量减少了一半。我不确定有多少差异是由虚拟机造成的,有多少是由 VS 通常生成比 gcc 更好的代码造成的,但我现在无法从 gcc 获得更准确的结果。

关于Java:高效计算大文件的SHA-256哈希值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1741545/

66 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com