Во время одной из моих сегодняшних лекций об Unity мы обсуждали обновление позиции нашего игрока, проверяя каждый кадр, нажата ли кнопка пользователя. Кто-то сказал, что это неэффективно, и вместо этого мы должны использовать прослушиватель событий.
Мой вопрос, независимо от языка программирования или ситуации, в которой он применяется, как работает прослушиватель событий?
Моя интуиция предполагала, что слушатель события постоянно проверяет, было ли событие запущено, а это означает, что в моем сценарии это не отличалось бы от проверки каждого кадра, если событие было запущено.
Судя по обсуждению в классе, слушатель событий работает по-другому.
Как работает слушатель событий?
event-programming
Гэри Холидей
источник
источник
Ответы:
В отличие от предоставленного вами примера опроса (где кнопка проверяется в каждом кадре), прослушиватель событий не проверяет, нажата ли кнопка вообще. Вместо этого он вызывается при нажатии кнопки.
Возможно, термин «слушатель событий» выбрасывает вас. Этот термин предполагает, что «слушатель» активно что-то делает, чтобы слушать, хотя на самом деле он вообще ничего не делает. «Слушатель» - это просто функция или метод, который подписан на событие. При возникновении события вызывается метод слушателя («обработчик события»).
Преимущество шаблона события заключается в том, что до нажатия кнопки фактически не требуется никаких затрат. Событие может быть обработано таким образом без контроля, потому что оно происходит от того, что мы называем «аппаратным прерыванием», которое на короткое время прерывает работающий код для запуска события.
Некоторые пользовательские интерфейсы и игровые среды используют так называемый «цикл сообщений», который ставит события в очередь на более поздний (обычно короткий) промежуток времени, но вам все еще нужно аппаратное прерывание, чтобы сначала поместить это событие в цикл сообщений.
источник
Прослушиватель событий похож на подписку на электронную рассылку (вы регистрируетесь, чтобы получать обновления, передача которых инициируется отправителем), а не бесконечно обновлять веб-страницу (где вы инициируете передачу информации).
Система событий реализована с использованием объектов событий, которые управляют списком подписчиков. Заинтересованные объекты (называемые подписчиками , слушателями , делегатами и т. Д.) Могут подписаться на получение информации о событии, вызвав метод, который присоединяется к событию, в результате чего событие добавляет их в свой список. Всякий раз , когда событие уволено (терминология может также включать в себя: называется , срабатывает , вызывается , запуск и т.д.), он вызывает соответствующий метод по каждому из абонентов, чтобы сообщить им о событии, проходя по любому контекстной информации , которую они должны понимать , что случилось.
источник
Короткий, неудовлетворительный ответ заключается в том, что приложение получает сигнал (событие) и что процедура вызывается только в этой точке.
Более длинное объяснение немного сложнее.
Откуда происходят клиентские события?
Каждое современное приложение † имеет внутренний, обычно полузакрытый «цикл событий», который отправляет события нужным компонентам, которые должны их получать. Например, событие «щелчок» отправляется кнопке, поверхность которой видна в текущих координатах мыши. Это на простейшем уровне. На самом деле ОС выполняет большую часть этой диспетчеризации, так как некоторые события и некоторые компоненты будут получать сообщения напрямую.
Откуда происходят события приложения?
Операционные системы отправляют события по мере их возникновения. Они делают это реактивно, будучи уведомленными их собственными водителями.
Как драйверы генерируют события?
Я не эксперт, но наверняка некоторые используют прерывания ЦП: аппаратное обеспечение, которым они управляют, повышает нагрузку на ЦП при появлении новых данных; CPU запускает драйвер, который обрабатывает входящие данные, которые в конечном итоге генерируют (очередь) событий для отправки, а затем возвращают управление обратно в ОС.
Итак, как вы видите, ваше приложение на самом деле не работает все время вообще. Это набор процедур, которые запускаются ОС (своего рода) по мере возникновения событий, но в остальное время ничего не делают.
† Существуют заметные исключения, например, игры на один раз, которые могут изменить ситуацию
источник
терминология
событие : тип вещей, которые могут произойти.
запуск события : конкретное возникновение события; событие происходит.
слушатель события : что-то, что высматривает события.
обработчик события : то, что происходит, когда слушатель события обнаруживает срабатывание события.
подписчик события : ответ, который должен вызвать обработчик события.
Эти определения не зависят от реализации, поэтому они могут быть реализованы разными способами.
Некоторые из этих терминов обычно ошибочно принимают за синонимы, поскольку пользователям часто не нужно различать их.
Общие сценарии
Программирование-логика событий.
Событие , когда какой - либо метод вызывается.
Обжиг события является конкретным вызовом к этому методу.
Прослушиватель событий является крюк в методе события , который называется на каждом выстреле событий , который вызывает обработчик события.
Обработчик событий вызывает набор абонентов событий.
Подписчик события (ы) выполнять любые действия (s) система означает , что произойдет в ответ на возникновение события.
Внешние события.
Событие является внешним событием , которое может быть выведено из наблюдаемых.
Стрельбы события , когда , что внешнее событие может быть признаны , имевшее место.
Слушатель события как - то обнаруживает пуски события, часто путем опроса наблюдаемой (s), то он вызывает обработчик события при обнаружении события стрельбы.
Обработчик событий вызывает набор абонентов событий.
Подписчик события (ы) выполнять любые действия (s) система означает , что произойдет в ответ на возникновение события.
Опрос и вставка хуков в механизм запуска события
Дело в том, что опросы часто не нужны. Это связано с тем, что прослушиватели событий могут быть реализованы путем автоматического вызова обработчиков событий, вызывающих обработчик событий, что часто является наиболее эффективным способом реализации вещей, когда события являются событиями системного уровня.
По аналогии, вам не нужно каждый день проверять почтовый ящик на наличие почты, если работник почты стучит в вашу дверь и вручает почту прямо вам.
Однако слушатели событий могут также работать опросом. Опрос не обязательно должен проверять определенное значение или другое наблюдаемое; это может быть более сложным. Но, в целом, смысл опроса заключается в том, чтобы сделать вывод, когда произошло какое-то событие, на которое можно ответить.
По аналогии, вы должны проверять свой почтовый ящик каждый день, когда почтовый работник просто бросает в него почту. Вам не пришлось бы выполнять эту работу по опросу, если бы вы могли проинструктировать почтового работника постучать в вашу дверь, но это часто невозможно.
Логика цепочки событий
Во многих языках программирования вы можете написать событие, которое вызывается только при нажатии клавиши на клавиатуре или в определенное время. Хотя это внешние события, вам не нужно их опрашивать. Почему?
Это потому, что операционная система опрашивает вас. Например, Windows проверяет такие вещи, как изменения состояния клавиатуры, и если она их обнаруживает, она вызывает абонентов событий. Итак, когда вы подписываетесь на событие нажатия клавиатуры, вы фактически подписываетесь на событие, которое само является подписчиком события, которое опрашивает.
По аналогии, скажем, что вы живете в многоквартирном комплексе, и почтовый работник отправляет почту в общую зону приема почты. Затем работник, похожий на операционную систему, может проверить эту почту для всех, доставляя почту в квартиры тех, кто что-то получил. Это избавляет всех остальных от необходимости опроса области получения почты.
Как вы и подозревали, событие может работать через опрос. И если событие каким-то образом связано с внешними событиями, например нажатием клавиши клавиатуры, опрос должен произойти в какой-то момент.
Также верно, что события не обязательно должны включать опрос. Например, если событие происходит при нажатии кнопки, то прослушиватель событий этой кнопки - это метод, который может вызвать среда графического интерфейса пользователя, когда он определяет, что нажатие кнопки мыши касается кнопки. В этом случае опрос все еще должен был произойти для обнаружения щелчка мыши, но слушатель мыши - более пассивный элемент, связанный с примитивным механизмом опроса через цепочку событий.
Обновление: на аппаратном опросе низкого уровня
Оказывается, что USB-устройства и другие современные коммуникационные протоколы имеют довольно увлекательный сетевой набор протоколов для взаимодействия, позволяющий устройствам ввода-вывода, включая клавиатуры и мыши, участвовать в специальных топологиях.
Интересно, что « прерывания » являются довольно обязательными, синхронными вещами, поэтому они не обрабатывают специальные сетевые топологии. Чтобы исправить это, « прерывания » были обобщены в асинхронные высокоприоритетные пакеты, называемые « транзакциями прерывания » (в контексте USB) или « прерываниями с сигналом сообщения » (в контексте PCI). Этот протокол описан в спецификации USB:
Суть в том, что устройства ввода-вывода и коммуникационные компоненты (например, концентраторы USB) в основном действуют как сетевые устройства. Итак, они отправляют сообщения, что требует опроса их портов и тому подобное. Это устраняет необходимость в выделенных аппаратных линиях.
Операционные системы , такие как Windows , кажется, обрабатывать сам процесс опроса, например , как описано в документации MSDN для
USB_ENDPOINT_DESCRIPTOR
«с , который описывает , как управлять тем, как часто для Windows опрашивает контроллер USB хост для прерывания / изохронными сообщений:Новые протоколы подключения монитора, такие как DisplayPort, похоже, делают то же самое:
Эта абстракция допускает некоторые полезные функции, такие как запуск 3 мониторов из одного соединения:
Концептуально, суть в том, что механизмы опроса допускают более обобщенную последовательную связь, что замечательно, когда вам нужна более общая функциональность. Таким образом, аппаратное обеспечение и ОС делают большой опрос для логической системы. Затем потребители, которые подписываются на события, могут наслаждаться теми деталями, которые обрабатываются для них системой более низкого уровня, без необходимости писать свои собственные протоколы опроса / передачи сообщений.
В конечном счете, такие события, как нажатия клавиш, проходят довольно интересную серию событий, прежде чем перейти к обязательному механизму запуска событий на уровне программного обеспечения.
источник
Тянуть против толчка
Есть две основные стратегии, чтобы проверить, произошло ли событие или достигнуто определенное состояние. Например, представьте, что вас ждет важная доставка:
Метод извлечения (также называемый опросом) проще: вы можете реализовать его без каких-либо специальных функций. С другой стороны, это часто менее эффективно, так как вы рискуете делать дополнительные проверки, не показывая им ничего.
С другой стороны, push- подход обычно более эффективен: ваш код запускается только тогда, когда ему есть чем заняться. С другой стороны, требуется, чтобы у вас был механизм для регистрации слушателя / наблюдателя / обратного вызова 1 .
1 К сожалению, моему почтальону обычно не хватает такого механизма.
источник
О единстве в отдельности - нет другого способа проверить ввод игрока, кроме как опросить его каждый кадр. Чтобы создать прослушиватель событий, вам все равно понадобится такой объект, как «система событий» или «менеджер событий», чтобы выполнить опрос, поэтому он только перенесет проблему в другой класс.
Конечно, если у вас есть менеджер событий, у вас есть только один класс, опрашивающий входные данные в каждом кадре, но это не дает каких-либо очевидных преимуществ в производительности, поскольку теперь этот класс должен перебирать слушателей и вызывать их, что в зависимости от вашей игры дизайн (например, сколько слушателей и как часто игрок использует ввод) может быть более дорогостоящим.
Помимо всего этого, помните золотое правило - преждевременная оптимизация является корнем всего зла , что особенно верно в видеоиграх, где часто процесс рендеринга каждого кадра стоит так дорого, что небольшие оптимизации сценариев, подобные этой, совершенно незначительны
источник
Если у вас нет какой-либо поддержки в вашей ОС / платформе, которая обрабатывает такие события, как нажатие кнопки, переполнение таймера или прибытие сообщения, - вам все равно придется реализовать этот шаблон прослушивателя событий, используя опрос (где-то внизу).
Но не отвлекайтесь от этого шаблона проектирования только потому, что у вас нет сразу же выигрыша в производительности. Вот причины, по которым вы должны использовать его независимо от того, поддерживаете ли вы поддержку обработки событий или нет.
Вывод - вам повезло поучаствовать в дискуссии и выучили одну альтернативу опросу. Ищите возможность применить эту концепцию на практике, и вы оцените, насколько элегантным может быть код.
источник
Большинство циклов событий построены над примитивом мультиплексирования с опросом, предоставляемым операционной системой. В Linux этот примитив часто является системным вызовом (
poll
2) (но может быть и старымselect
). В приложениях с графическим интерфейсом сервер дисплея (например, Xorg или Wayland ) связывается (через сокет (7) или канал (7) ) с вашим приложением. Читайте также о системных протоколах и архитектуре X Window .Такие примитивы опроса эффективны; ядро на практике разбудит ваш процесс, когда будет сделан некоторый ввод (и обработано некоторое прерывание).
Конкретно, ваша библиотека инструментария виджетов связывается с вашим сервером отображения, ожидая сообщений и отправляя эти сообщения вашим виджетам. Библиотеки инструментария, такие как Qt или GTK , довольно сложны (миллионы строк исходного кода). Ваша клавиатура и мышь обрабатываются только процессом сервера дисплея (который преобразует такие входные данные в сообщения о событиях, отправляемые клиентским приложениям).
(Я упрощаю; на самом деле все гораздо сложнее)
источник
В системе, основанной исключительно на опросе, подсистеме, которая может захотеть узнать, когда происходит какое-то конкретное действие, потребуется запускать некоторый код в любое время, когда это действие может произойти. Если существует много подсистем, каждая из которых должна реагировать в течение 10 мс после какого-то не обязательно уникального события, все они должны будут проверять, по крайней мере, 100 раз в секунду, произошло ли их событие. Если эти подсистемы находятся в разных процессах потоков (или, что еще хуже, процессов), для этого потребуется переключение в каждом таком потоке или процесс 100x / сек.
Если многие вещи, которые будут отслеживать приложения, довольно похожи, может быть более эффективно иметь централизованную подсистему мониторинга - возможно, управляемую таблицей - которая может наблюдать за многими вещами и наблюдать, изменилась ли какая-либо из них. Например, если имеется 32 коммутатора, у платформы может быть функция считывать все 32 коммутатора одновременно в одно слово, что позволяет коду монитора проверять, изменились ли какие-либо коммутаторы между опросами и - если нет - нет беспокоиться о том, какой код может быть им интересен.
Если существует много подсистем, которые хотели бы получать уведомления при изменении чего-либо, выделенная подсистема мониторинга уведомляет другие подсистемы, когда происходят события, в которых они заинтересованы, может быть более эффективным, чем каждая подсистема опрашивает свои собственные события. Однако настройка выделенной подсистемы мониторинга в тех случаях, когда никто не заинтересован в каких-либо событиях, будет представлять собой пустую трату ресурсов. Если есть только несколько подсистем, которые заинтересованы в событиях, стоимость того, чтобы они наблюдали за интересующими их событиями, может быть меньше, чем стоимость установки специализированной подсистемы мониторинга общего назначения, но безубыточность точка будет значительно отличаться между различными платформами.
источник
Слушатель событий похож на слух, ожидающий сообщения. Когда событие происходит, подпрограмма, выбранная в качестве прослушивателя событий, работает с использованием аргументов события.
Всегда есть два важных данных: момент, когда событие происходит, и объект, где это событие происходит. Другой аргумент - больше данных о том, что случилось.
Слушатель события определяет реакцию на то, что происходит.
источник
Слушатель событий следует шаблону публикации / подписки (как подписчик)
В своей простейшей форме объект публикации поддерживает список инструкций подписчиков, которые необходимо выполнить, когда что-то нужно опубликовать.
У него будет какой-то
subscribe(x)
метод, где x зависит от того, как обработчик события предназначен для обработки события. Когда вызывается подписка (х), х добавляется в список издателей инструкций / ссылок подписчиков.Издатель может содержать все, некоторые или никакие из логики для обработки события. Это может просто потребовать ссылки на подписчиков, чтобы уведомить / преобразовать их с его определенной логикой, когда происходит событие. Он может не содержать логику и требовать подписчиков объектов (методов / прослушивателей событий), которые могут обработать событие. Скорее всего, они содержат смесь обоих.
Когда происходит событие, издатель выполняет итерацию и выполняет свою логику для каждого элемента в своем списке инструкций / ссылок подписчиков.
Независимо от того, насколько сложным выглядит обработчик событий, по своей сути он следует этому простому шаблону.
Примеры
Для примера прослушивателя событий вы предоставляете метод / функцию / инструкцию / прослушиватель событий для метода subscribe () обработчика событий. Обработчик событий добавляет метод в свой список обратных вызовов подписчика. Когда происходит событие, обработчик события перебирает свой список и выполняет каждый обратный вызов.
Например, когда вы подписываетесь на новостную рассылку Stack Exchange, ссылка на ваш профиль будет добавлена в таблицу подписчиков базы данных. Когда придет время публиковать новостную рассылку, ссылка будет использоваться для заполнения шаблона новостной рассылки и будет отправлена на вашу электронную почту. В этом случае x - это просто ссылка на вас, а у издателя есть набор внутренних инструкций, используемых для всех подписчиков.
источник