Вопрос производительности Java-программы - PullRequest
0 голосов
/ 28 апреля 2011

У меня есть Java-программа со следующей логикой:

i) Open a socket server and wait for messages from client

ii) Read messages received(fixed length records of about 233 bytes).

iii) on each message receive, call a process function.

iv) process function does follwing
 - add the record to the string builder.

 - if (length of stringbuilder > configured buffer size) {

   process this buffer

   } else {

      add the new record to buffer

   }

Теперь, когда я пробую эту программу с 1 миллионом записей, каждый из которых занимает 233 байта, для завершения требуется около 5 минут 30 секунд. Я хочу сократить это время. Большая часть времени здесь тратится впустую в этой функции процесса.

Я проверял, могу ли я получить несколько советов о том, как реорганизовать этот процесс () для повышения производительности. Мой вариант использования - получить записи и прочитать их, пока они не достигнут настроенного размера буфера (например, 50 МБ, 500 МБ или 1 ГБ). Как только они достигнут этого размера, обработайте его и запишите в файловую систему.

Ответы [ 4 ]

0 голосов
/ 24 января 2013

Некоторые проверки работоспособности конверта:

  • Вы отправляете 233 * 1M байт = 1.864 Гб через сокет, это займет разное количество времени в зависимости от вашей пропускной способности и сетевой карты, но для набросать некоторые исходные цифры, если вы получили нужную карту на 100 Мб за 20 секунд до того, как вас поразит реальная задержка в сети. В действительности это может быть намного выше, если вы не используете localhost или не используете отличное оборудование и возможности подключения.
  • Кодирование 233 байтов в строку занимает примерно 260 нс (на моей машине) с использованием новой строки (байты []), поэтому вы смотрите на 1M * 0,25us = 250 миллис.

Таким образом, байты в String не проблема, и я также думаю, что StringBuilder.append не так уж и плох (он копирует массив char в). Вы будете использовать большое количество памяти для всех этих строк и байтовых буферов, и это может привести к некоторому замедлению. Чтобы избежать оттока памяти, вы можете использовать Charset.newDecoder, чтобы получить декодер (сохранить и повторно использовать) и записать ByteBuffer, который вы отключили, непосредственно в многоразовый CharBuffer. Вы упоминаете о некотором форматировании строк, это может быть дорогостоящим, если сделано неправильно, но если вы не делаете что-то сложное, я не думаю, что это проблема.

Более вероятная причина вашей проблемы - сетевая задержка, вы можете проверить эту теорию, написав фиктивную программу, которая просто читает данные и выбрасывает их. Другой вероятный подозрение - часть вашего кода, которая записывает данные в файл или на диск, но без дополнительной информации трудно помочь. Кроме того, если вы новичок в профилировании, вы можете использовать ручную синхронизацию для проверки своих теорий:

long start = System.nanotime();
process(data);
long took = System.nanotime() - start;

Подведите итог, сколько времени вы провели в процессе, и у вас есть представление о том, куда ушло время.

0 голосов
/ 28 апреля 2011

Пара «микрооптимизаций»:

  1. Создайте свой StringBuilder с правильным начальным размером (например, 1 ГБ).
  2. Не пересоздавать StringBuilder каждый раз; повторно использовать его, установив setLength (0)

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

  • Почему данные хранятся в промежуточном буфере? Если все, что вы делаете, - это записываете его в файловую систему, то лучше ли было бы писать по одной записи за раз, используя BufferedWriter?
  • Должны ли сообщения обрабатываться в порядке их поступления? Если нет, вы можете использовать ExecutorService для распараллеливания обработки.
0 голосов
/ 28 апреля 2011

Я подозреваю, что большую часть 5:30 минут можно записать на сетевые накладные расходы той или иной формы.Я бы порекомендовал следующее (сначала самое важное):

  • Если вы используете UDP, переключитесь на TCP.Для чего-то подобного вы, вероятно, получите лучшую пропускную способность при использовании транспорта на основе потоков, чем транспорта на основе сообщений.

  • На концах клиента и сервера убедитесь, что вы обернули потоки сокетов буферизованными потоками.

  • Если клиент и серверна том же хосте используйте петлевой IP-адрес (например, 127.0.0.1).

  • Если обработка на стороне сервера интенсивно использует ЦП (и у вас несколько ядер), выполните обработку вотдельный поток для потока, который читает сообщения.

  • Рассмотрите возможность использования NIO для чтения / записи данных.

  • Не конвертируйте данныек символьной форме на стороне сервера ... хотя, если это действительно текст, это затруднит обработку.


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

0 голосов
/ 28 апреля 2011

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

Нам потребуется больше информации об обработке, если у вас есть только одно ядро.Ваш процессор привязан в вашем тесте?Какая ОС и т.д?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...