如何在java中更快地计算sha256?

发布于 2024-12-11 16:40:23 字数 1695 浏览 0 评论 0原文

我发现在java中计算sha256很慢。例如,它比python慢​​。我编写了两个简单的基准测试来计算 1GB 零的 sha256。在这两种情况下,结果是相同且正确的,但 python 时间为 5653ms,java 时间为 8623ms(慢了 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

I have found out that calculating sha256 in java is slow. For example, it is slower than python. I wrote two simple benchmarks that calculate sha256 of 1GB of zeroes. In both cases the result is the same and correct, but the python time is 5653ms and the java time is 8623ms(53% slower). The result is similar every time and this is an important difference for me.

How to make the calculation in java faster?

Benchmarks:

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)

results:

~> java BenchmarkSha256
49bc20df15e412a64472421e13fe86ff1c5165e18b2afccf160d4dc19fe68a14
8623 ms

~> python BenchmarkSha256.py 
49bc20df15e412a64472421e13fe86ff1c5165e18b2afccf160d4dc19fe68a14
5653 ms

versions of java and 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

宣告ˉ结束 2024-12-18 16:40:23

我对以下 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 很容易成为两个最快的实现。在我的跑步中有 9/10,Apache Commons 以微弱优势击败了 Guava。我用于此测试的代码可在此处获取。

请注意,运行此测试后,我开始想知道是否可以通过利用 CPU 指令集来加快速度(Intel 有 SHA 扩展)。我不确定是否有一种 JVM 方法可以在没有 JNI 或 JNA 的情况下执行此操作。我在此处创建了另一个问题。

更新:我发现的另一个选项是 Amazon Corretto 加密货币提供商 (ACCP)。代码可在此处获取。

ACCP到底是什么?

ACCP 实现了标准 Java 加密架构 (JCA) 接口,并用 OpenSSL 项目中的 libcrypto 提供的实现替换了默认的 Java 加密实现。 ACCP 使您能够充分利用汇编级和 CPU 级性能调优,从而在多个服务和产品中显着降低成本、减少延迟并提高吞吐量,如下面的示例所示。

I ran a test on the following SHA-256 implementations: Java built-in, Groovy built-in, Apache Commons, Guava, and Bouncy Castle. My results on one run are here:

>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

This was run on an Intel i5 8th Gen. Apache and Guava were easily to two fastest implementations. Apache Commons narrowly beat out Guava on 9/10 of my runs. My code for this test is available here.

Note that after running this test I started to wonder if you could go even faster by tapping into the CPU instruction set (Intel has SHA extensions). I'm not sure there is a JVM way to do this without JNI or JNA. I created another question here.

Update: Another option I found is the Amazon Corretto Crypto Provider (ACCP). Code available here.

What exactly is ACCP?

ACCP implements the standard Java Cryptography Architecture (JCA) interfaces and replaces the default Java cryptographic implementations with those provided by libcrypto from the OpenSSL project. ACCP allows you to take full advantage of assembly-level and CPU-level performance tuning, to gain significant cost reduction, latency reduction, and higher throughput across multiple services and products, as shown in the examples below.

雨巷深深 2024-12-18 16:40:23

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

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

Have you tried feeding in the data incrementally? You can use messageDigest.update() with the bytes and then get the final digest with messageDigest.digest()?

Allocating a 1GB array in memory is a fairly chunky operation. You may find that smaller incremental updates are faster in the end.

骄傲 2024-12-18 16:40:23

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

为了稍微清理一下这个问题,只需在代码本身的每次实际 MD5 计算之前和之后获取两个时间样本。

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

Well, unless you are doing this to compare two command line programs, this is not the best test. Primarily, these numbers are being polluted by the vast differences in overhead associated with each program. VM start times will vary. Memory allocation speeds will vary.

To clean this up a bit, simply take two time samples before and after each actual MD5 calculation within the code itself.

This will actually measure performance of the hashing operation itself.

帝王念 2024-12-18 16:40:23

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

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

While you might be able to improve the performance of the Java tool a bit, the Python implementation will usually be faster because it is likely delegating to assembled libraries which run with significantly better performance.

If your project does not have any other significant dependencies on Java, I'd recommend going with the Python implementation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文