Какая очередь блокирования Java является самой эффективной для сценариев единственного потребителя единственного производителя

Переменные Python знают свои типы в зависимости от типа назначенной им переменной. Это язык динамических типов. В вашем коде интерпретатор видит foo1 = foo1[0] = [0] и в конце находит значение, равное [0]. Это список с одним элементом 0. Теперь это присваивается первому элементу списка foo1 - foo1[0] = [0]. Но поскольку foo1 уже объявлено, он создает объект, который имеет указатель на себя, и, следовательно, foo1 получает самоссылку бесконечно, причем самый внутренний список имеет 0.

Структура списка foo1 будет таким же, когда код foo1 = foo1[0].

Объект foo1 вошел в бесконечный цикл с собственной ссылкой.

39
задан Uri 10 June 2009 в 17:09
поделиться

6 ответов

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

DelayQueue , LinkedBlockingDeque , PriorityBlockingQueue и SynchronousQueue созданы для особые случаи, требующие дополнительной функциональности; они не имеют смысла в этом сценарии.

Остается только ArrayBlockingQueue и LinkedBlockingQueue . Если вы знаете, как определить, нужен ли вам ArrayList или LinkedList , вы, вероятно, сможете сами ответить на этот вопрос.

Обратите внимание, что в LinkedBlockingQueue , " связанные узлы динамически создаются при каждой вставке "; это может подтолкнуть вас к ArrayBlockingQueue .

и SynchronousQueue созданы для особых случаев, требующих дополнительных функций; они не имеют смысла в этом сценарии.

Остается только ArrayBlockingQueue и LinkedBlockingQueue . Если вы знаете, как определить, нужен ли вам ArrayList или LinkedList , вы, вероятно, сможете сами ответить на этот вопрос.

Обратите внимание, что в LinkedBlockingQueue , " связанные узлы динамически создаются при каждой вставке "; это может подтолкнуть вас к ArrayBlockingQueue .

и SynchronousQueue созданы для особых случаев, требующих дополнительных функций; они не имеют смысла в этом сценарии.

Остается только ArrayBlockingQueue и LinkedBlockingQueue . Если вы знаете, как определить, нужен ли вам ArrayList или LinkedList , вы, вероятно, сможете сами ответить на этот вопрос.

Обратите внимание, что в LinkedBlockingQueue , " связанные узлы динамически создаются при каждой вставке "; это может подтолкнуть вас к ArrayBlockingQueue .

Если вы знаете, как определить, нужен ли вам ArrayList или LinkedList , вы, вероятно, сможете сами ответить на этот вопрос.

Обратите внимание, что в LinkedBlockingQueue , " связанные узлы динамически создаются при каждой вставке "; это может подтолкнуть вас к ArrayBlockingQueue .

Если вы знаете, как определить, нужен ли вам ArrayList или LinkedList , вы, вероятно, сможете сами ответить на этот вопрос.

Обратите внимание, что в LinkedBlockingQueue , " связанные узлы динамически создаются при каждой вставке "; это может подтолкнуть вас к ArrayBlockingQueue .

32
ответ дан 27 November 2019 в 02:42
поделиться

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

Если вы сделаете это, вы сможете получить стабильные тайминги для операций до 99,99% времени. Это не настоящий режим реального времени, но может быть достаточно близким. В торговой системе стоимость использования Java вместо C может стоить 100 фунтов в день, однако стоимость разработки на C / C ++, а не на Java, вероятно, будет намного выше. например, с точки зрения гибкости, которую он дает нам, и количества ошибок, которые он сохраняет.

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

К сожалению, для передачи объекта между потоками в Java через ArrayBlockingQueue на серверах, над которыми я работаю, требуется около 8 микросекунд, и я предлагаю вам проверить это на своих серверах. Простой тест - передать System.nanoTime () между потоками и посмотреть, сколько времени это займет.

ArrayBlockingQueue имеет «особенность», при которой он создает объект для каждого добавленного элемента (хотя для этого нет особых причин так и сделай) Так что, если вы найдете стандартную реализацию, которая этого не делает, дайте мне знать.

12
ответ дан 27 November 2019 в 02:42
поделиться

LinkedBlockingQueue будет иметь стоимость вставки O (1), если не будет задержки выделения памяти. Очень большой ArrayBlockingQueue будет иметь стоимость вставки O (1), если система не заблокирована из-за сборки мусора; однако при заполнении он будет блокироваться при вставке.

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

5
ответ дан 27 November 2019 в 02:42
поделиться

Я согласен с замечанием Эндрю Даффи о том, что реализация такой системы с ограничениями по времени в java может быть ошибкой. В любом случае, предполагая, что вы состоите в браке с JVM и не ожидаете, что эта очередь будет заполнена (т. Е. Потребитель может справиться с нагрузкой), я думаю, вам лучше всего подойдет пользовательская реализация, подобная ArrayBlockingQueue но урезан / оптимизирован для сценария одного производителя / потребителя. В частности, мне нравится идея вращения на стороне производителя для ожидания свободного места, а не блокировки.

Я обратился к источникам java.concurrent за руководством и составил проект этого алгоритма. ...

Мне это кажется неплохим, но он полностью не тестировался и, возможно, не быстрее на практике (возможно, не революционный, но я сам проверял :-). В любом случае, мне это понравилось ... Можете ли вы найти недостаток?

Псевдокод:

private final ReentrantLock takeLock = new ReentrantLock();
private final Condition notEmpty = takeLock.newCondition();
private final E[] buffer;
private int head = 0
private int tail = 0;

public void put(E e) {
  if (e == null) throw NullPointerException();

  while (buffer[tail] != null) {
    // spin, wait for space...  hurry up, consumer!
    // open Q: would a tight/empty loop be superior here?
    Thread.sleep(1);
  }

  buffer[tail] = e;
  tail = (tail + 1) % buffer.length;

  if (count.getAndIncrement() == 0)  {
    sync(takeLock) { // this is pseudocode -- should be lock/try/finally/unlock
      notEmpty.signal();
    }
  }
}

public E take() {
  sync(takeLock) {
    while (count.get() == 0) notEmpty.await();
  }
  E item = buffer[head];
  buffer[head] = null;
  count.decrement();
  head = (head + 1) % buffer.length;

  return item;
}
4
ответ дан 27 November 2019 в 02:42
поделиться

ArrayBlockingQueue, вероятно, будет быстрее, поскольку вам не нужно создавать узлы ссылок при вставке. Обратите внимание, однако, что ArrayBlockingQueue имеет фиксированную длину, если вы хотите, чтобы ваша очередь увеличивалась произвольно (по крайней мере до Integer.MAX_INT), вам придется использовать LinkedBlockingQueue (если вы не хотите выделить массив элементов Integer.MAX_INT) .

2
ответ дан 27 November 2019 в 02:42
поделиться

Если требования к времени настолько жесткие, вам, вероятно, потребуется провести обширный тест на том же самом оборудовании, чтобы определить наиболее подходящее.

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

3
ответ дан 27 November 2019 в 02:42
поделиться
Другие вопросы по тегам:

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