Убедитесь, что у вас есть правильный адрес электронной почты перед отправкой сообщений электронной почты. Если кто-то задает неправильный адрес электронной почты при регистрации, побейте их по голове как можно скорее.
Всегда включайте четкую информацию о том, как отказаться от подписки, в КАЖДОЙ электронной почте.
Это не позволит пользователям помечать ваши письма как спам, потому что «отмена подписки» слишком сложна.
Не нужно подписывать пользователя для отказа от подписки, это должен быть уникальный URL-адрес для отмены подписки на 1 клик. ]Мое объяснение может не решить вашу проблему, поскольку оно во многом зависит от вашей реальной среды выполнения, но когда я запускаю ваш код в своей системе, пропускная способность ограничивается дисковым вводом-выводом, а не расчет хеша. Проблема не решается переключением на NIO, а просто вызвана тем, что вы читаете файл очень маленькими частями (16 КБ). Увеличение размера буфера (бафф) в моей системе до 1 МБ вместо 16 КБ увеличивает пропускную способность более чем вдвое, но при> 50 МБ / с я все еще ограничен скоростью диска и не могу полностью загрузить одно ядро ЦП.
BTW : Вы можете значительно упростить свою реализацию, обернув DigestInputStream вокруг FileInputStream, прочтите файл и получите рассчитанный хэш из DigestInputStream вместо того, чтобы вручную перетасовывать данные из RandomAccessFile в MessageDigest, как в вашем коде.
Я провел несколько тестов производительности со старыми версиями Java, и, похоже, есть существенная разница между Java 5 и Java 6 здесь. Однако я не уверен, оптимизирована ли реализация SHA или виртуальная машина выполняет код намного быстрее. Пропускная способность, которую я получаю с разными версиями Java (буфер 1 МБ), составляет:
Мне было немного любопытно, как влияет ассемблер на реализацию CryptoPP SHA, поскольку результаты тестов показывают, что алгоритм SHA-256 требует на Opteron всего 15,8 циклов ЦП на байт. К сожалению, мне не удалось собрать CryptoPP с помощью gcc на cygwin (сборка прошла успешно, но сгенерированный exe сразу же не удалось), но построил тест производительности с VS2005 (конфигурация выпуска по умолчанию) с поддержкой ассемблера в CryptoPP и без нее и по сравнению с Java SHA реализация в буфере в памяти, без учета дискового ввода-вывода, я получаю следующие результаты на Phenom 2,5 ГГц:
Оба теста вычисляют хэш SHA для массива пустых байтов размером 4 ГБ, выполняя итерацию по нему кусками по 1 МБ, которые передаются в MessageDigest # update ( Java) или SHA256 от CryptoPP. Функция обновления (C ++).
Я смог собрать и протестировать CryptoPP с gcc 4.4.1 (-O3) на виртуальной машине под управлением Linux и получил только ок. вдвое меньше пропускной способности по сравнению с результатами VS exe. Я не уверен, какая разница вносится в виртуальную машину, а какая из-за того, что VS обычно производит лучший код, чем gcc, но у меня нет возможности получить более точные результаты прямо сейчас.
Возможно, первое, что нужно сделать сегодня, - это выяснить, где вы проводите больше всего времени? Можете ли вы запустить его через профилировщик и посмотреть, на что тратится больше всего времени.
Возможные улучшения:
Я предлагаю вы используете профилировщик, такой как JProfiler, или тот, который интегрирован в Netbeans (бесплатно), чтобы узнать, где на самом деле тратится время, и сконцентрироваться на этой части.
Просто дикая догадка - не уверен, поможет ли это - но пробовали ли вы Серверная ВМ? Попробуйте запустить приложение с java -сервер
и посмотрите, поможет ли это вам. Серверная виртуальная машина более агрессивно компилирует Java-код в собственный, чем клиентская виртуальная машина по умолчанию.
Просто дикая догадка - не уверен, поможет ли это - но пробовали ли вы виртуальную машину сервера? Попробуйте запустить приложение с java -сервер
и посмотрите, поможет ли это вам. Серверная виртуальная машина более агрессивно компилирует Java-код в собственный, чем клиентская виртуальная машина по умолчанию.
Просто дикая догадка - не уверен, поможет ли это - но пробовали ли вы виртуальную машину сервера? Попробуйте запустить приложение с java -сервер
и посмотрите, поможет ли это вам. Серверная виртуальная машина более агрессивно компилирует Java-код в собственный, чем клиентская виртуальная машина по умолчанию.
Раньше Java работала примерно в 10 раз медленнее, чем тот же код C ++. В настоящее время почти в 2 раза медленнее. Я думаю, что то, с чем вы столкнулись, - это просто фундаментальная часть Java. JVM станут быстрее, особенно по мере открытия новых JIT-технологий, но вам будет трудно выполнять C.
Пробовали ли вы альтернативные JVM и / или компиляторы? Раньше я получал лучшую производительность с JRocket , но с меньшей стабильностью. То же самое для использования jikes поверх javac.
Поскольку у вас явно есть рабочий Реализация C ++ является быстрой, вы можете построить мост JNI и использовать реальную реализацию C ++ или, может быть, вы могли бы попробовать не изобретать велосипед, тем более что он большой, и использовать готовую библиотеку, такую как BouncyCastle , который был создан для решения всех криптографических потребностей вашей программы.
Я думаю, что эта разница в производительности может быть связана только с платформой. Попробуйте изменить размер буфера и посмотрите, есть ли улучшения. Если нет, я бы выбрал JNI (собственный интерфейс Java) . Просто вызовите реализацию C ++ из Java.
Основная причина, по которой ваш код работает так медленно, заключается в том, что вы используете RandomAccessFile, который всегда был достаточно медленным. Я предлагаю использовать "BufferedInputStream", чтобы вы могли извлечь выгоду из всей мощи кэширования на уровне операционной системы для disk-i/o.
Код должен выглядеть примерно так:
public static byte [] hash(MessageDigest digest, BufferedInputStream in, int bufferSize) throws IOException {
byte [] buffer = new byte[bufferSize];
int sizeRead = -1;
while ((sizeRead = in.read(buffer)) != -1) {
digest.update(buffer, 0, sizeRead);
}
in.close();
byte [] hash = null;
hash = new byte[digest.getDigestLength()];
hash = digest.digest();
return hash;
}