【问题标题】:How to calculate sha256 faster in java?如何在java中更快地计算sha256?
【发布时间】:2011-12-12 09:48:17
【问题描述】:

我发现在 java 中计算 sha256 很慢。例如,它比 python 慢。我写了两个简单的基准来计算 1GB 零的 sha256。在这两种情况下,结果都是相同且正确的,但是 python 时间是 5653 毫秒,而 java 时间是 8623 毫秒(慢了 53%)。结果每次都相似,这对我来说是一个重要的区别。

如何让java中的计算更快?

基准测试:

Java:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class BenchmarkSha256 {

  public static void main(String... args) throws NoSuchAlgorithmException {
    int size = 1024 * 1024;
    byte[] bytes = new byte[size];
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    long startTime = System.nanoTime();
    for (int i = 0; i < 1024; i++)
      md.update(bytes, 0, size);
    long endTime = System.nanoTime();
    System.out.println(String.format("%1$064x", new java.math.BigInteger(1, md.digest())));
    System.out.println(String.format("%d ms", (endTime - startTime) / 1000000));
  }

}

Python:

#!/usr/bin/env python

import hashlib
import time

size = 1024 * 1024
bytes = bytearray(size)
md = hashlib.sha256()
startTime = time.time()
for i in range(0, 1024):
  md.update(bytes)
endTime = time.time()
print "%s\n%d ms" % (md.hexdigest(), (endTime - startTime) * 1000)

结果:

~> java BenchmarkSha256
49bc20df15e412a64472421e13fe86ff1c5165e18b2afccf160d4dc19fe68a14
8623 ms

~> python BenchmarkSha256.py 
49bc20df15e412a64472421e13fe86ff1c5165e18b2afccf160d4dc19fe68a14
5653 ms

java 和 python 的版本:

~> java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)

~> python --version
Python 2.7

【问题讨论】:

  • 您是否排除了两种情况下启动环境的成本,或者您是否对整个程序时间感兴趣而不是算法时间? (两者都是值得询问的问题,但它们是非常不同的指标。)
  • @DonalFellows 我只对算法时间感兴趣。在这种规模下,启动时间并不那么重要。我试图评论“md.update(bytes, 0, size);” java代码中的一行,除计算外,整个过程时间为0.4s。即使减去这个时间,它仍然更慢。
  • @DonalFellows 我认为这不是重复的,因为在引用的问题/答案中涉及很多文件 I/O,这里我对纯哈希计算感兴趣。
  • 我怀疑摘要使用 Java 而不是汇编库。您可以使用 Java 中的 cryptopp.com/benchmarks.html

标签: java optimization sha256 sha


【解决方案1】:

我对以下 SHA-256 实现进行了测试:Java 内置、Groovy 内置、Apache Commons、Guava 和 Bouncy Castle。我的一次运行结果在这里:

>groovy hash_comp.groovy
Hashing 1000000 iterations of SHA-256
time java: 2688         372023.8095238095 hashes/sec
time groovy: 1948       513347.0225872690 hashes/sec
time apache: 867        1153402.5374855825 hashes/sec
time guava: 953         1049317.9433368311 hashes/sec
time bouncy: 1890       529100.5291005291 hashes/sec

这是在 Intel i5 第 8 代上运行的。Apache 和 Guava 很容易成为两个最快的实现。 Apache Commons 在我 9/10 的运行中以微弱优势击败了 Guava。我的这个测试代码是可用的here

请注意,在运行此测试后,我开始怀疑您是否可以通过利用 CPU 指令集来更快(英特尔有 SHA extensions)。我不确定在没有 JNI 或 JNA 的情况下是否有 JVM 方法可以做到这一点。我创建了另一个问题here

更新:我发现的另一个选项是Amazon Corretto Crypto Provider (ACCP)。可用代码here

究竟什么是 ACCP?

ACCP 实现标准的 Java 加密体系结构 (JCA) 接口,并将默认的 Java 加密实现替换为 OpenSSL 项目中 libcrypto 提供的实现。 ACCP 允许您充分利用程序集级别和 CPU 级别的性能调整,从而显着降低成本、减少延迟并提高跨多种服务和产品的吞吐量,如下面的示例所示。

【讨论】:

    【解决方案2】:

    虽然您可能能够稍微提高 Java 工具的性能,但 Python 实现通常会更快,因为它很可能会委托给以显着更好的性能运行的组装库。

    如果您的项目对 Java 没有任何其他重要依赖项,我建议您使用 Python 实现。

    【讨论】:

    • 该项目仅是 java。 python 实现仅用于演示。问题是,如何用java更快地计算sha256?
    【解决方案3】:

    好吧,除非您这样做是为了比较两个命令行程序,否则这不是最好的测试。首先,这些数字受到与每个程序相关的巨大开销差异的影响。 VM 启动时间会有所不同。内存分配速度会有所不同。

    要稍微清理一下,只需在代码本身中每次实际 MD5 计算之前和之后进行两次采样。

    这实际上将衡量散列操作本身的性能。

    【讨论】:

    • 谢谢,我做到了,现在java版本只测量哈希计算的时间。问题已更新且仍然有效。
    • @Hristo:你也必须对 Python 代码做同样的事情,否则仍然不公平(但反过来也不公平)。
    • @allingeek 我应该注意到您的“答案”实际上是一条评论。这应该是赞成的评论,但不是答案。
    • @Hristo:现在你有有效的数字,我说这是一个骗子的问题告诉你为什么。 :-)
    • @DonalFellows 这些数字和预期的一样,基本相同。这个问题什么也没告诉我:)
    【解决方案4】:

    您是否尝试过以增量方式输入数据?您可以将messageDigest.update() 与字节一起使用,然后使用messageDigest.digest() 获取最终摘要?

    在内存中分配一个 1GB 的数组是一个相当笨重的操作。您最终可能会发现较小的增量更新更快。

    【讨论】:

    • 我修改了java版本只测量时间进行计算,结果基本一样。我将尝试增量更新变体并发布结果。
    • 现在代码已更新为完全做到这一点:增量馈送和最终摘要,问题仍然相同:java 速度较慢。
    • 我们或许应该给 Java 更多的机会,让它 JIT 优化。也许对代码运行几百次(在同一个 VM 启动中)进行计时会显示出一些差异。可能增加默认堆大小也会有所帮助(减少 GC 压力)? Python 实现只是对 C 库的一个薄包装吗?
    • 代码“md.update(...)”已经运行了 1024 次...我尝试增加堆大小 - 没有效果。我不知道 python 的实现,我只是在两个平台上都采用了最直接的方法。
    • @JeffFoster 是的,afaik python 在 OpenSSL 周围使用了一个瘦包装器,所以我们基本上是在对 OpenSSL 的 C 实现和 Java 之间的差异进行基准测试(大概不是使用 JNI 实现的?)
    猜你喜欢
    • 2019-08-16
    • 2018-09-13
    • 2012-03-28
    • 1970-01-01
    • 2012-07-11
    • 1970-01-01
    • 2020-07-24
    • 2020-02-09
    • 1970-01-01
    相关资源
    最近更新 更多