2013-10-11 3 views
10

Я разрабатываю Java-загрузчик для двоичных данных. Эти данные передаются через текстовый протокол (UU-encoded). Для сетевой задачи используется netty. Двоичные данные разбиваются сервером на многие тысячи небольших пакетов и отправляются клиенту (то есть приложение Java).Java: более быстрая альтернатива String (byte [])

От netty Я получаю объект ChannelBuffer каждый раз при получении нового сообщения (данных). Теперь мне нужно обработать эти данные, помимо других задач мне нужно проверить заголовок пакета, поступающего с сервера (например, строка состояния HTTP). Для этого я вызываю ChannelBuffer.array() для получения массива byte[]. Затем этот массив можно преобразовать в строку через new String(byte[]) и легко проверить (например, сравнить) его содержимое (опять же, как сравнение с сообщением статуса «200» в HTTP).

Программное обеспечение, которое я пишу, использует несколько потоков/соединений, поэтому я получаю несколько пакетов от netty параллельно.

Это обычно работает нормально, однако при профилировании приложения я заметил, что когда соединение с сервером хорошее, а данные поступают очень быстро, то это преобразование в объект String кажется узким местом. В таких случаях использование ЦП близко к 100%, и в соответствии с профилировщиком очень много времени тратится на вызов этого конструктора String(byte[]).

Я искал лучший способ получить от ChannelBuffer до String, и заметил, что у первого также есть метод toString(). Однако этот метод еще медленнее, чем конструктор String(byte[]).

Итак, мой вопрос: кто-нибудь из вас знает лучшую альтернативу для достижения того, что я делаю?

+0

Почему? Просто отправьте байты как можно быстрее. Забудьте о uuencoding; забыть о расщеплении. TCP уже выполняет разделение, и он знает намного больше об оптимальном размере пакета в текущем соединении, чем вы. – EJP

ответ

13

Возможно, вы можете полностью пропустить преобразование строк? У вас могут быть константы, содержащие массивы байтов для ваших значений сравнения и проверки массива-массива вместо 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); 
+1

+1 Создание строк может быть дороже, чем вы могли ожидать. Избегайте их создания, и вы можете значительно повысить производительность. –

+0

Это отличный ответ, спасибо вам большое! – Matthias

1

Некоторые из проверки вы делаете, возможно, просто посмотрите на части буфера. Если бы вы могли использовать альтернативную форму конструктора Струнный:

new String(byteArray, startCol, length) 

Это может означать намного меньше байт преобразуются в строку.

Ваш пример поиска «200» в сообщении будет примером.

Вы можете обнаружить, что вы можете использовать длину массива байтов в качестве ключа. Если некоторые сообщения длинны, и вы ищете короткий, игнорируете длинные и не конвертируете в символы. Или что-то типа того.

Наряду с тем, что сказал @EricGrunzke, частично глядя в буфер байтов, чтобы отфильтровать некоторые сообщения и обнаружить, что вам не нужно, чтобы преобразовать их из байтов в символы.

Если байты ASCII символов, преобразование в символы может быть быстрее, если использовать кодировки «ASCII» вместо того, чтобы все, что по умолчанию для вашего сервера:

new String(bytes, "ASCII") 

могущества Быстрее в этом случае.

На самом деле, вы можете выбрать кодировку для преобразования байтового символа в некотором организованном порядке, что ускоряет работу.

0

В зависимости от того, что вы пытаетесь сделать, есть несколько вариантов:

  1. Если вы просто пытаетесь получить статус ответа, то вы не можете просто позвонить getStatus()? Вероятно, это будет быстрее, чем получение строки.
  2. Если вы пытаетесь преобразовать буфер, то, предполагая, что вы знаете, что это будет ASCII, который звучит так, как вы, просто оставите данные в виде байта [] и преобразуйте ваш метод UUDecode для работы с байтом [] вместо строки.

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

Смежные вопросы