我发现在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 "%sn%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
您是否尝试过增量输入数据?您可以使用messageDigest.update()
来处理字节,然后使用messageDigest.digest()
来获得最终摘要?
在内存中分配1GB数组是一个相当大的操作。您可能会发现较小的增量更新最终会更快。
我对以下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第八代上运行的。Apache和Guava很容易成为两个最快的实现。Apache Commons在9/10的测试中以微弱优势击败了Guava。我的测试代码可以在这里找到。
注意,在运行这个测试之后,我开始怀疑是否可以通过访问CPU指令集(Intel有SHA扩展)来更快地运行。我不确定在没有JNI或JNA的情况下,JVM是否有办法做到这一点。我在这里创造了另一个问题。
更新:我发现的另一个选项是亚马逊Corretto加密提供商(ACCP)。
ACCP到底是什么?
ACCP实现了标准的Java加密体系结构(JCA)接口,并将默认的Java加密实现替换为OpenSSL项目中libcrypto提供的实现。ACCP允许您充分利用汇编级和cpu级的性能调优,从而在多个服务和产品之间显著降低成本、减少延迟和提高吞吐量,如下面的示例所示。
除非您这样做是为了比较两个命令行程序,否则这不是最好的测试。首先,这些数字受到与每个程序相关的开销的巨大差异的影响。虚拟机启动时间会有所不同。内存分配速度会有所不同。
为了稍微清理一下,只需在代码本身的每次实际MD5计算之前和之后分别进行两次时间采样。
这将实际测量哈希操作本身的性能。
虽然您可能能够稍微提高Java工具的性能,但Python实现通常会更快,因为它可能委托给运行性能明显更好的汇编库。
如果您的项目对Java没有任何其他重要的依赖,我建议您使用Python实现。