У чому різниця між: асинхронною, неблокуючою, архітектурою подій-бази?


84
  1. Яка різниця між:

    • Асинхронний ,
    • Неблокуючий , та
    • Архітектури на основі подій ?
  2. Чи може щось бути як асинхронним, так і неблокуючимзаснованим на подіях )?

  3. Що найважливіше в програмуванні - мати щось: асинхронне, неблокувальне та / або база подій (або всі 3)?

Якби ви могли навести приклади, це було б чудово.

Це запитання задається, тому що я читав цю чудову статтю StackOverflow на подібну тему, але вона не відповідає на мої запитання вище.

Відповіді:


91

Асинхронний Асинхронний буквально означає не синхронний. Електронна пошта є асинхронною. Ви надсилаєте лист, і не очікуєте отримати відповідь ЗАРАЗ. Але це не є блокуючим. По суті, це означає архітектуру, коли "компоненти" надсилають повідомлення один одному, не очікуючи негайної відповіді. Запити HTTP є синхронними. Надішліть запит і отримайте відповідь.

Неблокуючий Цей термін в основному використовується з введенням-виведенням. Це означає, що коли ви здійснюєте системний виклик, він негайно повернеться з будь-яким результатом, не маючи призупинення потоку (з великою ймовірністю). Наприклад, неблокуючі дзвінки читання / запису повертаються з тим, що вони можуть зробити, і очікуйте, що абонент знову виконає виклик. Наприклад, try_lock - це неблокуючий дзвінок. Він заблокується, лише якщо його можна отримати. Звичайна семантика системних викликів блокує. read зачекає, поки отримає деякі дані, і переведе виклик потоку в режим сну.

Основа подій Цей термін походить від libevent. незаблоковані дзвінки для читання / запису самі по собі марні, оскільки вони не говорять вам "коли", якщо ви повинні передзвонити їм (повторити спробу). select / epoll / IOCompletionPort тощо - це різні механізми виявлення з ОС, коли "очікується, що ці виклики повернуть" цікаві "дані. libevent та інші подібні бібліотеки надають обгортки над цими засобами моніторингу подій, що надаються різними ОС, та надають послідовний API для роботи, який працює в операційних системах. Неблокуючий введення-випуск поєднується з Event-base.

Я думаю, що ці терміни збігаються. Наприклад, протокол HTTP є синхронним, але реалізація HTTP з використанням неблокуючого вводу-виводу може бути асинхронною. Знову ж неблокуючий виклик API, такий як read / write / try_lock, є синхронним (він негайно дає відповідь), але "обробка даних" є асинхронним.


2
Хороший момент щодо неблокування, що вимагає постійного опитування, тоді як асинхронізація може бути побудованою на основі push.
Олександр Торстлінг

Ви визначили синхронні як отримання негайної відповіді, але коли я гуглю синхронно, усі словники визначають це як «відбувається одночасно», а не як «негайна відповідь».
IntelliData,

4
Як мене заблокують, коли я надсилаю електронне повідомлення, але не очікую відповіді? Я можу займатися своїми справами, чекаючи відповіді.
Корай Тугай

20

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

Розглянемо послідовний порт, з якого код хоче отримати 1000 байт.

В архівуючій архіві блокування код буде чекати, поки не надійде або 1000 байт, або він вирішить відмовитись.

В архітектурі з асинхронним читанням код повідомляє драйверу, що хоче 1000 байт, і буде повідомлений, коли надійде 1000 байт.

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

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


5

Отже, щоб відповісти на ваше перше та друге запитання:

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

Тепер код Async / Non-blocking звучить абсолютно фантастично, і це так. Але у мене є слова попередження. Async / Non-blocking чудово підходять при роботі в обмежених середовищах, наприклад, в мобільному телефоні ... розгляньте обмеженість процесора / пам'яті. Це також добре для інтерфейсної розробки, де ваш код повинен якось реагувати на віджет UI.

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

У той момент, коли ваш код запитує щось, що займе деякий час, щоб відповісти, ваша ОС знає, що вона може займатися іншими справами. Ваш код - процес, нитка або еквівалент, блоки. Ваш код абсолютно не пам’ятає, що ще відбувається в ОС, поки він чекає встановлення з’єднання з мережею, або поки він чекає цієї відповіді від HTTP-запиту, або поки він чекає, що зчитування / запис файлу, і так далі. Ваш код може "просто" чекати клацання миші. Тоді, що насправді відбувалося в той час, це те, що ваша ОС безперешкодно керує, планує та реагує на "події" - речі, на які шукає ОС, такі як управління пам’яттю, введення-виведення (клавіатура, миша. Диск, Інтернет), інші завдання, відновлення несправностей тощо.

Операційні системи затяті. Вони дійсно добре приховують усі складні асинхронні / неблокуючі речі від вас, програміста. І саме так більшість програмістів дійшли до того місця, де ми сьогодні перебуваємо за допомогою програмного забезпечення. Зараз ми досягаємо обмежень процесора, люди кажуть, що можна робити паралельно для підвищення продуктивності. Це означає, що Async / non-blocking здається дуже сприятливою справою, і так, якщо ваше програмне забезпечення вимагає цього, я можу погодитися.

Якщо ви пишете внутрішній веб-сервер, то будьте обережні. Пам'ятайте, що ви можете масштабувати горизонтально набагато дешевше. Netflix / Amazon / Google / Facebook, однак, є очевидними винятками з цього правила, лише тому, що їм виходить дешевше використовувати менше обладнання.

Я скажу вам, чому асинхронний / неблокуючий код - це кошмар із фоновими системами ....

1) Це стає відмовою в обслуговуванні щодо продуктивності ... Вам потрібно думати НАБАГАТО більше, і на цьому шляху ви робите багато помилок.

2) Сліди стеку в реактивному коді стають нерозбірливими - важко зрозуміти, що називається що, коли, чому і як. Удачі вам у налагодженні.

3) Вам доведеться більше думати про те, як щось не вдається, особливо коли багато речей повертаються з ладу, як ви їх надіслали. У старому світі ви робили по одній справі.

4) Складніше перевірити.

5) Важче підтримувати.

6) Це боляче. Програмування повинно приносити радість і задоволення. Біль подобається лише мазохістам. Люди, які пишуть паралельні / реактивні рамки, є садистами.

І так, я писав як синхронізацію, так і асинхронізацію. Я вважаю за краще синхронний, оскільки 99,99 фонових програм можуть пройти за допомогою цієї парадигми. Фронтальні програми потребують реактивного коду, без сумнівів, і це завжди було способом.

  1. Так, код може бути асинхронним, неблокуючим та заснованим на подіях.

  2. Найголовніше у програмуванні - це переконатися, що ваш код працює та реагує протягом прийнятного часу. Дотримуйтесь цього ключового принципу, і ви не можете помилитися.


** ОНОВЛЕННЯ ** Після гри з Go та роздумів про канали та підпрограми, я повинен сказати, що мені насправді подобається робити мій код більш одночасним, тому що конструкції мови сприймають усі проблеми від садистських фреймворків. У нас є "безпечне слово" у світі асинхронної обробки - і це "Іди!"
user924272

4

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

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

Читання одночасних даних не блокується (не потрібно блокувати), але синхронно. Навпаки, синхронний запис даних одночасно блокує (потрібно ексклюзивне блокування). Спосіб зробити його неблокуючим з точки зору основного потоку - зробити записи асинхронними та відкласти їх виконання.

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

Три терміни пов'язані, але для мене це різні поняття. Можливо, люди використовують їх дещо взаємозамінно.


2

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

Архітектура на основі подій базується на концепції коду, який виконується у відповідь на події, які запускаються. Час виконання коду, як правило, не є детермінованим, але події можуть викликати методи блокування; те, що система базується на подіях, не означає, що все, що вона робить, не блокується.

Як правило, асинхронна архітектура - це подія, що не блокує архітектуру.

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

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

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


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

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