Как быстрее рассчитать sha256 в java?

Я обнаружил, что вычисление sha256 в java происходит медленно. Например, он медленнее, чем python. Я написал два простых бенчмарка, вычисляющих sha256 из 1 ГБ нулей. В обоих случаях результат одинаковый и правильный, но время python составляет 5653 мс, а время java — 8623 мс (на 53% медленнее). Результат каждый раз одинаков и это важное отличие для меня.

Как сделать расчет в 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));
  }

}

Питон:

#!/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

person Hristo Hristov    schedule 21.10.2011    source источник
comment
Вы исключили затраты на запуск среды в обоих случаях или вас интересует время всей программы, а не время алгоритма? (Оба вопроса допустимы, но это очень разные показатели.)   -  person Donal Fellows    schedule 21.10.2011
comment
возможный дубликат Java: эффективное вычисление хэша SHA-256 большого файла   -  person Donal Fellows    schedule 21.10.2011
comment
@DonalFellows Меня интересует только время алгоритма. Время запуска не так важно в этом масштабе. Я попытался прокомментировать md.update(bytes, 0, size); строка в коде Java, а время составляет 0,4 с для всего процесса, кроме расчета. Даже если вычесть это время, оно все равно будет медленнее.   -  person Hristo Hristov    schedule 21.10.2011
comment
@DonalFellows Я думаю, что это не дубликат, потому что в указанном вопросе / ответе задействовано много файловых операций ввода-вывода, здесь меня интересует чистое вычисление хэша.   -  person Hristo Hristov    schedule 21.10.2011
comment
Я подозреваю, что дайджест использует Java, а не библиотеку сборки. Вы можете использовать cryptopp.com/benchmarks.html из Java.   -  person Peter Lawrey    schedule 21.10.2011


Ответы (4)


Вы пробовали вводить данные постепенно? Вы можете использовать messageDigest.update() с байтами, а затем получить окончательный дайджест с messageDigest.digest()?

Выделение массива размером 1 ГБ в памяти — довольно громоздкая операция. Вы можете обнаружить, что небольшие добавочные обновления в конце концов выполняются быстрее.

person Jeff Foster    schedule 21.10.2011
comment
Я изменил версию Java, чтобы измерить только время расчета, результат в основном тот же. Я попробую инкрементальный вариант обновления и опубликую результаты. - person Hristo Hristov; 21.10.2011
comment
Теперь код обновлен, чтобы делать именно это: инкрементная подача и окончательный дайджест, проблема все та же: java медленнее. - person Hristo Hristov; 21.10.2011
comment
Вероятно, нам следует дать Java больше шансов и позволить ей оптимизироваться JIT. Возможно, время выполнения кода несколько сотен раз (при одном и том же запуске виртуальной машины) покажет некоторые различия. Вероятно, увеличение размера кучи по умолчанию тоже поможет (меньшее давление GC)? Является ли реализация Python просто тонкой оболочкой над библиотекой C? - person Jeff Foster; 21.10.2011
comment
Код md.update(...) уже выполняется 1024 раза... Я пробовал увеличивать размер кучи - безрезультатно. Я не знаю о реализации Python, я просто выбрал самые простые способы сделать это на обеих платформах. - person Hristo Hristov; 21.10.2011
comment
@JeffFoster Да, afaik python использует тонкую оболочку вокруг OpenSSL, поэтому мы в основном сравниваем разницу между реализацией OpenSSL C и Java (которая, по-видимому, не реализована с использованием JNI?) - person Voo; 22.10.2011
comment
@Voo, мы ищем более быстрое решение для Java, эталонный тест просто для сравнения с чем-то. - person Hristo Hristov; 24.10.2011

Ну, если вы не делаете это для сравнения двух программ командной строки, это не лучший тест. Прежде всего, эти цифры искажены огромными различиями в накладных расходах, связанных с каждой программой. Время запуска ВМ будет разным. Скорость выделения памяти будет разной.

Чтобы немного почистить это, просто возьмите две выборки времени до и после каждого фактического вычисления MD5 в самом коде.

Это фактически будет измерять производительность самой операции хеширования.

person allingeek    schedule 21.10.2011
comment
Спасибо, я так и сделал, теперь java-версия измеряет время только для вычисления хэша. Вопрос обновлен и все еще актуален. - person Hristo Hristov; 21.10.2011
comment
@Hristo: Вы должны сделать то же самое и с кодом Python, иначе это все еще несправедливо (но несправедливо с другой стороны). - person Donal Fellows; 21.10.2011
comment
@allingeek Я должен отметить, что ваш ответ на самом деле является комментарием. Это должен быть комментарий, но не ответ. - person Hristo Hristov; 21.10.2011
comment
@Hristo: Теперь у вас есть действительные цифры, вопрос, который, как я сказал, был обманом, говорит вам почему. :-) - person Donal Fellows; 21.10.2011
comment
@DonalFellows Цифры, как и ожидалось, в основном одинаковы. Этот вопрос мне ни о чем не говорит :) - person Hristo Hristov; 21.10.2011

Я провел тест на следующих реализациях 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 с небольшим перевесом обошла Guava в 9/10 моих прогонах. Мой код для этого теста доступен здесь.

Обратите внимание, что после запуска этого теста я начал задаваться вопросом, можно ли работать еще быстрее, подключившись к набору инструкций ЦП (у Intel есть Расширения SHA). Я не уверен, что есть способ JVM сделать это без JNI или JNA. Я создал еще один вопрос здесь.

Обновление: я нашел еще один вариант: Amazon Corretto Crypto Provider (ACCP). Код доступен здесь.

Что такое ACCP?

ACCP реализует стандартные интерфейсы Java Cryptography Architecture (JCA) и заменяет криптографические реализации Java по умолчанию теми, которые предоставляются libcrypto из проекта OpenSSL. ACCP позволяет в полной мере воспользоваться преимуществами настройки производительности на уровне сборки и ЦП, добиться значительного снижения затрат, сокращения задержек и повышения пропускной способности для нескольких служб и продуктов, как показано в приведенных ниже примерах.

person Scott    schedule 16.10.2019

Хотя вы можете немного улучшить производительность инструмента Java, реализация Python обычно будет быстрее, потому что она, вероятно, делегирует собранные библиотеки, которые работают со значительно более высокой производительностью.

Если ваш проект не имеет каких-либо других существенных зависимостей от Java, я бы рекомендовал использовать реализацию Python.

person allingeek    schedule 21.10.2011
comment
Проект только java. Реализация Python предназначена только для демонстрации. Вопрос, как посчитать sha256 с java быстрее? - person Hristo Hristov; 21.10.2011