2017-02-16 12 views
3

Я на самом деле пытаюсь написать цикл событий для Nashorn (java 8), так что обратные вызовы от асинхронных операций (потоки, которые я запускаю, например, для подключения к удаленным службам или выполнения длительных вычислений) помещаться в очередь и выполняться последовательно (не параллельно). Я делаю это, помещая функции обратного вызова в ConcurrentLinkedQueue и используя ScheduledExecutorService в качестве цикла, который проверяет очередь на выполнение обратного вызова.Цикл событий в java

работает нормально, но мои вопросы:

1) как короткий интервал можно использовать без перетаскивания моего процессора? Я буду иметь несколько из них, и они должны быть независимыми друг от друга. Таким образом, может существовать 50 потоков, которые запускают собственный цикл событий. Этот исполнитель пытается выполнить свой готовый к выполнению каждого 10мс, например ....

Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(<cbRunnable>, 0, 10, TimeUnit.MILLISECONDS); 

2) Есть ли такой подход преимущества над:

while (true) { 
    // check queue and execute any callback... 
} 

3) Есть ли лучший способ?

+0

«не перетаскивая мой процессор» Можете ли вы объяснить, что именно это означает для вас? – ControlAltDel

+1

Как насчет использования блокирующей очереди вместо опроса? – RealSkeptic

+0

@ControlAltDel: Я имею в виду, что слишком много не нужно платить за процессор. Использование всех его циклов и т. Д. –

ответ

1

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

while (true) { 
    // check queue and execute any callback... 
} 

Если проверка очереди блоков, пока элемент не доступен, то это «самый эффективный» способ опроса, с точки зрения использования ЦП. Если проверка не блокируется, то вызывающий поток будет вращаться, и вы будете запускать один аппаратный поток на полную мощность в течение всего цикла - однако это исключает затраты на синхронизацию и даст вам абсолютное лучшее время ответа . Вот некоторые примеры:

Блокирование очереди (не менее таксировать на процессоре, но происходит за счет синхронизации)

Queue<T> q = new LinkedBlockingQueue<>(); 
... 
while(true){ 
    T t = q.take(); 
    //t will never be null, do something with it here. 
} 

неблокируемых очереди (наиболее нагружают ЦП, но нет затраты синхронизации)

Queue<T> q = new LinkedList<>(); 
... 
while(true){ 
    T t; 
    while((t = q.poll()) == null); //busy polling! 
    //t will never be null, do something with it here 
} 

ScheduledExecutorService

И наконец ... если вы в конечном итоге используете службу запланированного исполнителя, вы заставляете ненужное время ожидания между опросами. Это будет почти так же эффективно по сравнению с полной реализацией BlockingQueue, но вы также вынуждены использовать время ответа, вплоть до интервала планирования. Что «лучше» для вашего приложения будет зависеть от того, сможете ли вы позволить себе ждать минимального времени сна между опросами (я думаю, вы можете запланировать микросекунду ...?), Или если вам нужно что-то более быстрое, как занятый опрос схема.

+0

спасибо. Принял ваш ответ. Интересно, есть ли у вас (или кто-либо) какая-либо информация о том, какая минимальная задержка будет для параметра ScheduledExecutorService.Я бы предположил, что в какой-то момент работа переключения «пробуждение/ожидание» повлияет на эффективность CPU, которая будет получена с помощью ScheduledExecutorService. Интересно, какой порог задержки - 100 мс, 10 мс, 1 мс? –