Перейти к основному содержанию

Eventloop

Обзор#

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

Характеристики#

  • Eventloop использует NIO в Java для обеспечения асинхронных вычислений и операций ввода-вывода (TCP, UDP).
  • Устраняет традиционное узкое место ввода-вывода для дальнейшей обработки бизнес-логики.
  • Может запускать несколько потоков eventloop на доступных ядрах.
  • Минимальная нагрузка на GC: массивы и байтовые буферы используются повторно.
  • Eventloop может планировать/откладывать определенные задачи для последующего выполнения или фонового выполнения.
  • Eventloop является однопоточным, поэтому у него нет накладных расходов на параллелизм.
note

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

Eventloop представляет собой бесконечный цикл, где каждый цикл выполняет все задания, которые предоставляются селектором или хранятся в специальных очередях. Каждая из этих задач должна быть небольшой, и ее выполнение называется tick.

Единственной блокирующей операцией бесконечного цикла Eventloop является Selector.select(). Эта операция выбирает набор ключей , соответствующие каналы которых готовы к операциям ввода/вывода. Eventloop асинхронно обрабатывает выбранные ключи и выполняет поставленные в очередь runnables в одном потоке.

Eventloop работает с различными типами задач, которые хранятся в отдельных очередях:

ЗадачиДобавлено черезОписание
Местные задачиEventloop#post Eventloop#postLater Eventloop#postNextДобавлено из текущего потока Eventloop
Одновременные задачиEventloop#execute Eventloop#submitДобавлено из других тем
Запланированные задачиEventloop#schedule Eventloop#delayПланируется выполнить позже
Фоновые задачиEventloop#scheduleBackground Eventloop#delayBackgroundТо же самое, что и Scheduled, но если остались только задания Background , Eventloop будет остановлен.

Eventloop будет остановлен, если его очереди с нефоновыми задачами пусты, селектор **** не имеет выбранных ключей и количество одновременных операций в других потоках равно 0. Чтобы предотвратить закрытие Eventloop, установите флаг keepAlive . Когда он установлен в значение true, Eventloop будет продолжать работать даже без заданий.

Примеры#

  • BasicExample - простой пример eventloop, который печатает сообщение "Hello World".
  • EventloopExample - представляет последовательность выполнения операций в eventloops.
note

Чтобы запустить примеры, необходимо клонировать ActiveJ с GitHub:

git clone https://github.com/activej/activej

И импортируйте его как проект Maven. Посмотрите тег v5.0-beta2. Перед запуском примеров выполните сборку проекта. Эти примеры расположены по адресу activej/examples/core/eventloop.

Основной пример#

В этом примере мы создаем eventloop, посылаем в него задачу (которая выводит сообщение "Hello World") и затем запускаем eventloop:

public final class BasicExample {  public static void main(String[] args) {    Eventloop eventloop = Eventloop.create();
    eventloop.post(() -> System.out.println("Hello World"));
    eventloop.run();  }}

Полный текст примера смотрите на GitHub.

Пример эвентлупа#

Этот пример показывает, как задачи планируются в циклах событий:

public final class EventloopExample {  public static void main(String[] args) {    Eventloop eventloop = Eventloop.create().withCurrentThread();    long startTime = currentTimeMillis();
    // #2    eventloop.delay(3000L, () -> System.out.println("Eventloop.delay(3000) is finished, time: " + (currentTimeMillis() - startTime)));    eventloop.delay(1000L, () -> System.out.println("Eventloop.delay(1000) is finished, time: " + (currentTimeMillis() - startTime)));    eventloop.delay(100L, () -> System.out.println("Eventloop.delay(100) is finished, time: " + (currentTimeMillis() - startTime)));
    // #1    System.out.println("Before running eventloop, time: " + (currentTimeMillis() - startTime));
    eventloop.run();  }}

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

Перед запуском eventloop, время: 2Eventloop.delay(100) завершен, время: 106Eventloop.delay(1000) завершен, время: 1001Eventloop.delay(3000) завершен, время: 3001

Полный текст примера смотрите на GitHub.