Java: более быстрая альтернатива String (byte [])
Я разрабатываю Java-загрузчик для двоичных данных. Эти данные передаются через текстовый протокол (UU-encoded). Для сетевой задачи используется Netty-библиотека. Двоичные данные разбиваются сервером на множество тысяч небольших пакетов и отправляются клиенту (то есть приложение Java).
От netty я получаю объект ChannelBuffer
каждый раз при получении нового сообщения (данных). Теперь мне нужно обработать эти данные, помимо других задач мне нужно проверить заголовок пакета, поступающего с сервера (например, строка состояния HTTP). Для этого я вызываю ChannelBuffer.array()
для получения массива byte[]
. Затем этот массив можно преобразовать в строку через new String(byte[])
и легко проверить (например, сравнить) его содержимое (опять же, как сравнение с сообщением статуса "200" в HTTP).
Программное обеспечение, которое я пишу, использует несколько потоков/соединений, так что я получаю несколько пакетов из netty параллельно.
Это обычно прекрасно работает, однако при профилировании приложения я заметил, что когда соединение с сервером хорошо, а данные поступают очень быстро, то это преобразование в объект String
кажется узким местом. В таких случаях использование ЦП близко к 100%, и в соответствии с профилировщиком очень много времени тратится на вызов этого конструктора String(byte[])
.
Я искал лучший способ получить от ChannelBuffer
до String
, и заметил, что у первого также есть метод toString()
. Однако этот метод еще медленнее конструктора String(byte[])
.
Итак, мой вопрос: кто-нибудь из вас знает лучшую альтернативу для достижения того, что я делаю?
Ответы
Ответ 1
Возможно, вы можете полностью пропустить преобразование String? У вас могут быть константы, содержащие массивы байтов для ваших значений сравнения и проверки array-to-array вместо String-to-String.
Вот пример быстрого кода для иллюстрации. В настоящее время вы делаете что-то вроде этого:
String http200 = "200";
// byte[] -> String conversion happens every time
String input = new String(ChannelBuffer.array());
return input.equals(http200);
Возможно, это быстрее:
// Ideally only convert String->byte[] once. Store these
// arrays somewhere and look them up instead of recalculating.
final byte[] http200 = "200".getBytes("UTF-8"); // Select the correct charset!
// Input doesn't have to be converted!
byte[] input = ChannelBuffer.array();
return Arrays.equals(input, http200);
Ответ 2
Некоторые из проверок, которые вы делаете, могут просто посмотреть на часть буфера. Если вы можете использовать альтернативную форму конструктора String:
new String(byteArray, startCol, length)
Это может означать, что намного меньше байтов преобразуется в строку.
Примером может служить пример поиска "200" в сообщении.
2
Вы можете обнаружить, что длину байтового массива можно использовать в качестве ключа. Если некоторые сообщения длинны, и вы ищете короткий, игнорируете длинные и не конвертируете в символы. Или что-то в этом роде.
3
Наряду с тем, что сказал @EricGrunzke, частично глядя в буфере байта, чтобы отфильтровать некоторые сообщения и найти, что вам не нужно преобразовывать их из байтов в символы.
4
Если ваши байты являются символами ASCII, преобразование в символы может быть быстрее, если вы используете кодировку "ASCII" вместо того, что по умолчанию для вашего сервера:
new String(bytes, "ASCII")
может быть быстрее в этом случае.
Фактически, вы можете выбрать и выбрать кодировку для преобразования байтового символа в некотором организованном порядке, что ускоряет работу.
Ответ 3
В зависимости от того, что вы пытаетесь сделать, есть несколько вариантов:
- Если вы просто пытаетесь получить статус ответа, вы не можете просто вызвать getStatus()? Это, вероятно, будет быстрее, чем извлечение строки.
- Если вы пытаетесь преобразовать буфер, то, предполагая, что вы знаете, что это будет ASCII, который звучит так, как вы, просто оставите данные в виде байта [] и преобразуйте ваш метод UUDecode для работы в байте [] вместо строки.
Самая большая стоимость преобразования строк, скорее всего, является копированием данных из массива байтов во внутренний массив char строки, это в сочетании с преобразованием, скорее всего, просто кучей работы, t нужно сделать.