Чи цикл подій є лише циклом for / while з оптимізованим опитуванням?


55

Я намагаюся зрозуміти, що таке цикл подій. Часто поясненням є те, що в циклі подій ви робите щось, поки не отримаєте сповіщення про те, що подія сталася. Потім ви впораєтеся з подією та продовжуєте робити те, що робили раніше.

Зобразити наведене визначення із прикладом. У мене є сервер, який 'слухає' в циклі подій, і коли виявлено з'єднання з сокетом, дані з нього зчитуються та відображаються, після чого сервер відновляється / починає слухати, як це робилося раніше.


Однак ця подія, яка відбувається, і ми отримуємо сповіщення "просто так" для мене дуже багато. Ви можете сказати: "Це не просто так", ви повинні зареєструвати слухача події ". Але що таке слухач подій, але функція, яка чомусь не повертається. Це у власному циклі, який чекає, коли буде повідомлено про подію? Чи повинен слухач події також зареєструвати слухача події? Де це закінчується?


Події - це приємна абстракція, з якою працювати, однак лише абстракція. Я вважаю, що врешті-решт опитування неминуче. Можливо, ми робимо це не в нашому коді, але нижчі рівні (реалізація мови програмування чи ОС) роблять це для нас.

Це в основному зводиться до наступного псевдо-коду, який працює десь досить низько, тому він не призводить до зайнятого очікування:

while(True):
    do stuff
    check if event has happened (poll)
    do other stuff

Це моє розуміння всієї ідеї, і я хотів би почути, чи правильно це. Я відкритий у прийнятті, що вся ідея принципово неправильна, і в цьому випадку мені хотілося б правильного пояснення.


3
Системи подій - це реалізація шаблону Observer . Розуміння закономірності повинно зміцнити ваше розуміння подій. Опитування не потрібно.
Стівен Еверс

1
Зрештою, так, навіть якщо мова будує його абстрактно.
GrandmasterB

@SteveEvers У своєму вікі-посиланні. Що EventSourceробити, якщо не запитувати вхід на клавіатурі?
TheMeaningfulEngineer

@Alan: Це може робити що завгодно, але для введення з клавіатури спеціально існують API, щоб зареєструвати ваше додаток як прослуховування подій на клавіатурі, який ви можете використовувати як джерело подій без участі в опитуванні. Звичайно, якщо ви зійдете досить далеко, USB завжди опитується, але припустимо, що ми використовуємо клавіатуру PS / 2, яка керується перериванням, і тоді у вас є стек введення клавіатури на основі подій з нульовим опитуванням.
Фоші

У мене були ці питання з років, але я не можу сказати, чому я ніколи не намагався його задавати. Дякую, я зараз задоволений розумінням @Karl Bielefeldt просвітив мене.
0xc0de

Відповіді:


54

Більшість циклів подій буде призупинено, якщо немає подій готових, а це означає, що операційна система не надасть завдання жодного часу виконання, поки подія не відбудеться.

Скажіть, подія - натискання клавіші. Ви можете запитати, чи є цикл десь в операційній системі, який перевіряє натискання клавіш. Відповідь - ні. Натискання клавіш генерує переривання , яке апаратно обробляє асинхронно. Так само для таймерів, рухів миші, пакета, що прибуває тощо.

Фактично для більшості операційних систем опитування подій є абстракцією. Апаратне забезпечення та ОС обробляють події асинхронно і ставлять їх у чергу, яку можуть опитувати програми. Ви справді бачите справжнє опитування на апаратному рівні у вбудованих системах, і навіть там не завжди.


4
Чи не є перервою зміна напруги на проводі? Чи може це викликати подію само собою чи треба опитувати штифт на значення напруги?
TheMeaningfulEngineer

8
Це може призвести до події само собою. Процесор розроблений саме так. Насправді процесор може бути пробуджений зі сну перервою.
Карл Білефельдт

2
Я плутаю заяву Most event loops will block. Як це вписується в "парадигму циклу подій, на противагу використанню потоків, використовує неблокуючі асинхронні виклики"?
TheMeaningfulEngineer

1
Якщо ви подивитеся на петлі подій для бібліотеки типу GTK +, вони перевіряють наявність нових подій, потім викликають обробників подій у циклі, але якщо таких немає, вони блокуються на семафорі або таймері чи щось подібне. Окремі розробники роблять власні цикли подій, які не блокуються в порожній черзі подій, але широко використовувані бібліотеки блокують. В іншому випадку петлі подій занадто неефективні.
Карл Білефельдт

1
Я припускаю, що ви могли б на це дивитись саме так, але це багаторазове введення в бібліотеку та / або ОС, а не код програми. Петлі подій абстрагують проблеми синхронізації для розробника програми.
Карл Білефельдт

13

Я вважаю слухача події не як функцію, що працює за своїм циклом, а як естафету з першим бігуном, який чекає на стартовий пістолет. Важливою причиною використання подій замість опитування є те, що вони ефективніші з циклами процесора. Чому? Подивіться на це з обладнання вгору (а не вихідний код вниз).

Розглянемо веб-сервер. Коли ваш сервер дзвонить listen()і блокує, ваш код займає своє місце як ретранслятор. Коли приходить перший пакет нового з'єднання, мережева карта починає гонку, перериваючи операційну систему. ОС виконує функцію обслуговування переривання (ISR), яка захоплює пакет. ISR передає естафету рутину вищого рівня, яка встановлює зв'язок. Після того, як з'єднання буде живим, ця програма передає естафету listen(), яка передає естафету вашому коду. У цей момент ви можете робити все, що завгодно, підключення. Наскільки ми знаємо, між перегонами кожен естафет міг їхати в паб. Сила абстракції події полягає в тому, що ваш код не повинен знати і не піклуватися про нього.

Деякі операційні системи включають в себе код обробки подій, який виконує свою частину гонки, передає естафету, а потім повертається до стартової точки, щоб чекати початку наступної гонки. У цьому сенсі обробка подій оптимізована для опитування у великій кількості одночасних циклів. Однак завжди є зовнішній тригер, який запускає процес. Слухач події - це не функція, яка не повертається, а функція, яка чекає цього зовнішнього тригера перед його запуском. Замість:

while(True):
    do stuff
    check if event has happened (poll)
    do other stuff

Я думаю про це як:

on(some event):    //I got the baton
     do stuff
     signal the next level up    //Pass the baton

і між signalі наступним разом, коли обробник запускається, концептуально не існує коду, який працює або циклічно.


Це має сенс, однак, що робить цикл подій, поки він чекає перерви? Якщо це блокує, чи не той "багатопотоковий" підхід, який є парадигмою, протилежною циклу подій?
TheMeaningfulEngineer

Якщо у вашого коду є цикл, forever: { select(); do stuff; }то ви кожен раз повторно вступаєте у гонку через цикл. Якщо ви робите це неодноразово з одного потоку або паралельно на окремих потоках або процесорах, я вважаю кожну подію власною расою. Наприклад, веб-браузер - це багатопотокова програма з декількома петлями подій в окремих потоках, принаймні одна для інтерфейсу користувача та одна для кожної завантажуваної сторінки. Питання, яке я задаю при кодуванні, "як я можу обробляти події досить швидко?" Іноді відповідь - це цикл, іноді нитки, часто - комбінація.
cxw

Я займаюся програмою на основі подій більше декількох десятків років, і вважаю цю відповідь дуже заплутаною. Щоб слухач працював, повинен бути цикл, який чекає події, а потім спрямовує його до всіх зареєстрованих слухачів. (Припустимо, що ми говоримо про програмне забезпечення, а не про апаратні перебої)
Брайан Оуклі,

8

Ні. Це не "оптимізоване опитування". Цикл подій використовує керований перериванням введення / вивід замість опитування.

У той час, до, для тощо, петлі опитують петлі.

"Опитування" - це процес багаторазової перевірки чогось. Оскільки код циклу виконується безперервно, і оскільки це невеликий, «щільний» цикл, процесору залишається мало часу для перемикання завдань і виконання всього іншого. Практично всі "зависання", "зависання", "блокування" або все, що ви хочете викликати, коли комп'ютер не реагує, є проявом коду, що застряг у ненавмисному циклі опитування. Інструментарій покаже 100% використання процесора.

Цикли подій, керовані перериванням, набагато ефективніші, ніж петлі опитування. Опитування - це надзвичайно марно використання циклів процесора, тому докладаються максимум зусиль для його усунення або мінімізації.

Однак для оптимізації якості коду більшість мов намагаються максимально наблизити парадигму циклу опитування до команд передачі подій, оскільки вони виконують функціонально подібні цілі в межах програми. Таким чином, коли опитування є більш звичним способом дочекатися натискання клавіші чи чогось іншого, недосвідченому користуватися ним легко і завершити програму, яка може працювати нормально, але нічого іншого не працює під час роботи. Це "заволоділо" машиною.

Як пояснено в інших відповідях, при передачі подій переривань по суті в CPU встановлюється "прапор", і процес "призупиняється" (не дозволяється запускати), поки цей прапор не буде змінений деяким іншим процесом (наприклад, клавіатурою драйвер змінює його, коли користувач натиснув клавішу). Якщо прапор - це фактичний апаратний стан, такий як лінія, яка "підтягується високо", це називається "переривання" або "апаратне переривання". Більшість, однак, реалізуються як просто пам'ять у процесорі або в основній пам'яті (RAM) і називаються "семафорами".

Семафори можна змінювати під управлінням програмним забезпеченням і таким чином забезпечувати дуже швидкий, простий механізм сигналізації між програмними процесами.

Однак перебої можуть змінюватися лише апаратними засобами. Найбільш повсюдне використання переривань - це те, що через рівні проміжки часу спрацьовує внутрішній тактовий чіп. Одне з незліченних видів програмних дій, що активуються перериваннями годинника, - це зміна семафорів.

Я багато чого вибув, але мусив десь зупинитися. Будь ласка, запитайте, чи потрібно більше деталей.


7

Зазвичай відповідь - це апаратне забезпечення, ОС і фонові потоки, якими ви не керуєте, змова, щоб це виглядало без зусиль. Мережева карта отримує деякі дані, які викликають перерву, щоб повідомити ЦП. Обробник переривання ОС обробляє його. Тоді фонова нитка, якою ви не керуєте (створена при реєстрації на подію і спить з моменту, коли ви зареєструвались на подію), прокидається ОС як частина обробки події та запускає ваш обробник подій.


7

Я збираюся суперечити всім іншим відповідям, які я бачу досі, і кажу "так" . Я думаю, що інші відповіді занадто ускладнюють справи. З концептуальної точки зору, всі петлі подій по суті є:

while <the_program_is_running> {
    event=wait_for_next_event()
    process_event(event)
}

Якщо ви намагаєтеся вперше зрозуміти петлі подій, думка про них як простий цикл не принесе шкоди. Деякий базовий фреймворк чекає, коли ОС доставить подію, вона потім направляє подію до одного або декількох обробників, потім чекає наступної події тощо. Це дійсно все, що є для цього з точки зору прикладного програмного забезпечення.


1
+1 за те, що це прямо. Але акцент робиться на «чекати»; Виконання цього коду зупинятиметься в першому рядку циклу і не триватиме, поки не відбудеться подія. Це відрізняється від зайнятого циклу опитування, який неодноразово перевіряється на подію, поки не відбудеться.
Том Панінг

1

Не всі тригери подій обробляються в циклі. Те, як я часто пишу власні двигуни подій, виглядатиме так:

interface Listener {
    void handle (EventInfo info);
}

List<Listener> registeredListeners

void triggerEvent (EventInfo info) {
    foreach (listener in registeredListeners) { // Memo 1
        listener.handle(info) // the handling may or may not be synchronous... your choice
    }
}

void somethingThatTriggersAnEvent () {
    blah
    blah
    blah
    triggerEvent(someGeneratedEventInfo)
    more blah
}

Зауважте, що хоча Memo 1 знаходиться в циклі, цикл призначений для сповіщення кожного слухача. Сам тригер події не обов'язково знаходиться в циклі.

Теоретично ключові події на рівні ОС можуть використовувати ту саму техніку (хоча я думаю, що вони часто проводять опитування замість цього? Я просто спекулюю тут) за умови, що ОС виставляє якийсь registerListenerAPI.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.