это - мое первое сообщение на 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.: жаль о моем плохом английском языке, я из Германии ;)
Ваш поток-производитель просто помещает больше элементов, чем потребляет , поэтому очередь в конечном итоге достигает предела мощности, поэтому производитель ждет.
Обобщая свой исходный ответ, так как теперь мы имеем в основном полную картину:
LinkedBlockingQueue
(в каждой очереди есть один), выполнив чрезвычайно быструю put ()
s, где даже непрерывные take () s
с нулевой дальнейшей обработкой не могут успевать. (Между прочим, это показывает, что в этой структуре, в любом случае на вашей JVM и машине, put (), по крайней мере, немного дороже, чем чтение). SynchronousQueue
, ConcurrentLinkedQueue
и предстоящую TransferQueue
из jsr166y).Некоторые предложения:
/ обновлено после того, как Джон В. правильно указал, что мой исходный ответ вводит в заблуждение
Ничего не могу сказать наверняка. Но вы можете попробовать изменить реализацию BlockingQueue
(просто в качестве эксперимента).
Вы устанавливаете начальную емкость 50 КБ и используете LinkedBlockingQueue
. Попробуйте ArrayBlockingQueue
с той же емкостью, вы также можете поиграть с параметром справедливым
.
Трудно сказать, что происходит, не зная чего-либо о процессе наполнения.
Если addMyMessage
вызывается реже - возможно, из-за проблем с производительностью в совершенно другой части вашего приложения - метод take
должен подождать.
Таким образом, похоже, что виноват take
, но на самом деле это заполняющая часть вашего приложения.
Нашел этот интересный пост о проблемах с производительностью из-за размера очереди и сборки мусора.
Обычно я бы рекомендовал не использовать LinkedBlockingQueue в области кода, чувствительной к производительности, используйте ArrayBlockingQueue. Это даст гораздо лучший профиль сборки мусора и более дружественный к кешу, чем LinkedBlockingQueue.
Попробуйте ArrayBlockingQueue и измерьте производительность.
Единственное преимущество LinkedBlockingQueue состоит в том, что он может быть неограниченным, однако это редко то, что вам действительно нужно. Если у вас есть случай, когда потребитель выходит из строя и очереди начинают резервное копирование, наличие ограниченных очередей позволяет системе плавно деградировать с риском возникновения OutOfMemoryErrors, которые могут возникнуть, если очереди не ограничены.
Возможно, на ваше приложение влияют изменения, связанные с блокировкой в Java 6, особенно функция «предвзятой блокировки».
Попробуйте отключить его с помощью переключателя -XX: -UseBiasedLocking
и посмотрите, имеет ли это значение.
См. Это для получения дополнительной информации: http://java.sun.com/performance/reference/whitepapers/6_performance.html
Вот несколько вещей, которые можно попробовать:
Замените LinkedBlockingQueue
на ArrayBlockingQueue
. У него нет висячих ссылок, поэтому он лучше ведет себя при заполнении очереди. В частности, учитывая реализацию LinkedBlockingQueue 1.6, полный сборщик мусора элементов не произойдет, пока очередь не станет фактически пустой.
Если сторона производителя постоянно не выполняет сторону потребителя, рассмотрите возможность использования стока
или стока
для выполнения операции «массового» взятия.
В качестве альтернативы, очередь может принимать массивы или списки объектов сообщений. Производитель заполняет список или массив объектами сообщений, и каждое размещение или прием перемещает несколько сообщений с одинаковыми накладными расходами на блокировку. Думайте об этом как о секретарше, который передает вам стопку сообщений «Пока вас не было», а не передает их вам по одному.