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 нужно сделать.