Как избежать занятого цикла while в управляемой событиями Java - PullRequest
2 голосов
/ 10 октября 2019

В настоящее время я разрабатываю свое управляемое событиями программное обеспечение Java следующим образом (это суть моего основного метода):

while(true) {
    Event event = eventListener.poll();
    if(event != null) {
        // do something
    } else {
        // do nothing as usual, but burn CPU time.
    }
}

В зависимости от того, что я создаю, eventListener может быть чем-тоон прослушивает внешний веб-сокет, опрашивает канал Redis на наличие обновлений или ожидает сообщения от другого процесса, сидящего в том же окне (возможно, через UDP / TCP / shm).

Я думаю, что этот занятый циклПодход тратит много процессорного времени, когда eventListener возвращает ноль (что происходит большую часть времени), так как он просто вращается. Тем не менее, я не знаю, как еще подойти к этой схеме, кроме добавления Thread.sleep каждой итерации, которая не является хорошим решением.

В идеале я хотел бы иметь метод:

void run(Event event) {
    // do something
}

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

Теперь я знаю, что есть библиотеки веб-сокетов, которые действительно могут это сделать, и я хочу знать, как я могу создать что-то подобное для себяи освободить мой процессор, чтобы сидеть там и тратить себя, ничего не делая?

Ответы [ 2 ]

4 голосов
/ 10 октября 2019

Вам необходимо использовать неблокирующий Java IO и может быть некоторой библиотекой, которая поддерживает высокоуровневую связь через Java NIO (например, netty , которая поддерживает связь в стиле NIO для HTTP, веб-сокетови redis среди многих других).

Вот краткое описание того, как работает NIO. То, что вы ищете, это Selector. Это позволяет ждать, пока данные на канале (который является абстракцией для файла или сетевого подключения и т. Д.) Не будут доступны. Это ожидание (Selector.select метод) блокируется, и ОС возобновляет процесс, когда некоторые данные доступны для чтения или выходной буфер для записи может получить новые данные.

Схематически код выглядит следующим образом:

Selector selector = createSelector();
Channel channel = createChannelForSocket();

SelectionKey key = channel.register(selector);

while(true) {

  int readyChannels = selector.select(TIMEOUT);

  if(readyChannels == 0) continue;

  Set<SelectionKey> selectedKeys = selector.selectedKeys();

  for(SelectionKey key : selectedKeys) {

    if (key.isReadable()) {
        readDataFromChannel(key.channel())
    } else if (key.isWritable()) {
        writeDataToChannel(key.channel())
    }

  }
}

С помощью netty у вас есть более высокоуровневый код, где вы определяете Handler, который имеет метод, подобный void channelRead(ChannelHandlerContext ctx, Object msg), который является своего рода читаемымпрослушиватель событий, который вы можете реализовать для прослушивания прочитанных событий.

netty имеет встроенный цикл, который похож на вышеприведенный пример, но для многих слушателей событий, и он передает эти события конкретным слушателям.

0 голосов
/ 13 ноября 2019

Если вы заинтересованы в использовании событийно-ориентированной архитектуры в масштабе. Возможно, вы захотите использовать надежную «шину событий», такую ​​как Apache Kafka или AWS SNS + SQS. Чтобы сделать это проще, вы можете использовать kalium.alkal.io. Это обеспечит беспроблемную де-сериализацию объектов POJO или protobuf. * ​​1001 *

kalium.on(Event.class, event -> {

   //doSomething with the event
});

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