Проблема производительности Java с LinkedBlockingQueue

это - мое первое сообщение на stackoverflow... Я надеюсь, что кто-то может помочь мне

У меня есть большая регрессия производительности с Java 6 LinkedBlockingQueue. В первом потоке я генерирую некоторые объекты, в которых я продвигаю очереди Во втором потоке, я вытаскиваю эти объекты. Регрессия производительности происходит когда take() метод LinkedBlockingQueue часто называется. Я контролировал целую программу и take() метод требовал большей части времени в целом. И пропускная способность идет от ~58Mb/s до 0.9Mb/s...

поп очереди и берет площадь методов, названную со статическим методом от этого класса

public class C_myMessageQueue {

    private static final LinkedBlockingQueue<C_myMessageObject> x_queue = new LinkedBlockingQueue<C_myMessageObject>( 50000 );

    /**
     * @param message
     * @throws InterruptedException
     * @throws NullPointerException
     */
    public static void addMyMessage( C_myMessageObject message )
            throws InterruptedException, NullPointerException {
        x_queue.put( message );
    }

    /**
     * @return Die erste message der MesseageQueue
     * @throws InterruptedException
     */
    public static C_myMessageObject getMyMessage() throws InterruptedException {
        return x_queue.take();
    }
}

как я могу настроиться take() метод для выполнения, по крайней мере, 25Mb/s, или там другой класс, который я могу использовать, который заблокируется, когда "очередь" будет полна или пуста.

с уважением

Bart

P.S.: жаль о моем плохом английском языке, я из Германии ;)

15
задан Roman 15 April 2010 в 12:11
поделиться

7 ответов

Ваш поток-производитель просто помещает больше элементов, чем потребляет , поэтому очередь в конечном итоге достигает предела мощности, поэтому производитель ждет.

Обобщая свой исходный ответ, так как теперь мы имеем в основном полную картину:

  • Вы достигли предела пропускной способности LinkedBlockingQueue (в каждой очереди есть один), выполнив чрезвычайно быструю put () s, где даже непрерывные take () s с нулевой дальнейшей обработкой не могут успевать. (Между прочим, это показывает, что в этой структуре, в любом случае на вашей JVM и машине, put (), по крайней мере, немного дороже, чем чтение).
  • Поскольку существует конкретная блокировка, которую блокируют потребители, размещение большего количества потоков потребителей не может помочь (если ваш потребитель фактически выполнял некоторую обработку и ограничивал пропускную способность, тогда добавление дополнительных потребителей могло бы помочь. Существуют более эффективные реализации очереди для сценарий с несколькими потребителями (или производителями), вы можете попробовать SynchronousQueue , ConcurrentLinkedQueue и предстоящую TransferQueue из jsr166y).

Некоторые предложения:

  • Постарайтесь создать более крупнозернистые объекты, чтобы накладные расходы на организацию очередей для каждого из них были сбалансированы с фактической работой, которая выгружается из производящего потока (в вашем случае кажется, что вы создаете много накладных расходов на связь для объектов, которые представляют незначительный объем работы)
  • Вы также можете попросить производителя помочь потребителю, разгрузив некоторую потребляющую работу (не так много смысла в бездействии, когда есть работа, которую нужно сделать).

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

16
ответ дан 1 December 2019 в 03:04
поделиться

Ничего не могу сказать наверняка. Но вы можете попробовать изменить реализацию BlockingQueue (просто в качестве эксперимента).

Вы устанавливаете начальную емкость 50 КБ и используете LinkedBlockingQueue . Попробуйте ArrayBlockingQueue с той же емкостью, вы также можете поиграть с параметром справедливым .

0
ответ дан 1 December 2019 в 03:04
поделиться

Трудно сказать, что происходит, не зная чего-либо о процессе наполнения.

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

Таким образом, похоже, что виноват take , но на самом деле это заполняющая часть вашего приложения.

1
ответ дан 1 December 2019 в 03:04
поделиться

Нашел этот интересный пост о проблемах с производительностью из-за размера очереди и сборки мусора.

1
ответ дан 1 December 2019 в 03:04
поделиться

Обычно я бы рекомендовал не использовать LinkedBlockingQueue в области кода, чувствительной к производительности, используйте ArrayBlockingQueue. Это даст гораздо лучший профиль сборки мусора и более дружественный к кешу, чем LinkedBlockingQueue.

Попробуйте ArrayBlockingQueue и измерьте производительность.

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

3
ответ дан 1 December 2019 в 03:04
поделиться

Возможно, на ваше приложение влияют изменения, связанные с блокировкой в ​​Java 6, особенно функция «предвзятой блокировки».

Попробуйте отключить его с помощью переключателя -XX: -UseBiasedLocking и посмотрите, имеет ли это значение.

См. Это для получения дополнительной информации: http://java.sun.com/performance/reference/whitepapers/6_performance.html

0
ответ дан 1 December 2019 в 03:04
поделиться

Вот несколько вещей, которые можно попробовать:

Замените LinkedBlockingQueue на ArrayBlockingQueue . У него нет висячих ссылок, поэтому он лучше ведет себя при заполнении очереди. В частности, учитывая реализацию LinkedBlockingQueue 1.6, полный сборщик мусора элементов не произойдет, пока очередь не станет фактически пустой.

Если сторона производителя постоянно не выполняет сторону потребителя, рассмотрите возможность использования стока или стока для выполнения операции «массового» взятия.

В качестве альтернативы, очередь может принимать массивы или списки объектов сообщений. Производитель заполняет список или массив объектами сообщений, и каждое размещение или прием перемещает несколько сообщений с одинаковыми накладными расходами на блокировку. Думайте об этом как о секретарше, который передает вам стопку сообщений «Пока вас не было», а не передает их вам по одному.

3
ответ дан 1 December 2019 в 03:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: