Яка різниця між асинхронними та неблокуючими дзвінками? Також між блокуванням і синхронними дзвінками (будь ласка, з прикладами)?
Яка різниця між асинхронними та неблокуючими дзвінками? Також між блокуванням і синхронними дзвінками (будь ласка, з прикладами)?
Відповіді:
За багатьох обставин вони різні назви для однієї речі, але в деяких контекстах вони зовсім інші. Так це залежить. Термінологія не застосовується повністю послідовно у всій галузі програмного забезпечення.
Наприклад, у класичному API сокетів, неблокуючий сокет - це те, що просто негайно повертається за допомогою спеціального повідомлення про помилку "заблокує", тоді як блокуючий сокет був би заблокований. Ви повинні використовувати окрему функцію, таку як, select
або poll
з'ясувати, коли настав час для повторної спроби.
Але асинхронні сокети (як це підтримується в сокетах Windows), або асинхронний IO-шаблон, який використовується в .NET, зручніші. Ви викликаєте метод для запуску операції, і фреймворк відкликає вас, коли це буде зроблено. Навіть тут є основні відмінності. Асинхронні сокети Win32 "маршалюють" свої результати на певний потік GUI, передаючи повідомлення Window, тоді як .NET асинхронний IO є безкоштовним потоком (ви не знаєте, на який потік буде викликаний зворотний дзвінок).
Тому вони не завжди означають те саме. Для дестиляції прикладу сокета можна сказати:
синхронний / асинхронний - це опис зв’язку між двома модулями.
блокування / неблокування полягає в описі ситуації одного модуля.
Приклад:
Модуль X: "Я".
Модуль Y: "книгарня".
X запитує Y: чи є у вас книга з назвою "c ++ праймер"?
1) блокування: перш ніж Y відповість X, X продовжує чекати відповіді. Тепер X (один модуль) блокується. X і Y - це два потоки або два процеси або одна нитка або один процес? ми не знаємо.
2) незаблокування: перш ніж Y відповість на X, X просто залишає там і робити інші речі. X може повертатися кожні дві хвилини, щоб перевірити, чи Y закінчив свою роботу? Або X не повернеться, поки Y не подзвонить йому? Ми не знаємо. Ми знаємо лише, що X може робити інші речі до того, як Y закінчить свою роботу. Тут X (один модуль) не блокує. X і Y - це два потоки або два процеси або один процес? ми не знаємо. Але ми впевнені, що X і Y не могли бути однією ниткою.
3) синхронний: перш ніж Y відповість X, X продовжує чекати відповіді. Це означає, що X не може продовжуватись, поки Y не закінчить свою роботу. Тепер ми говоримо: X і Y (два модулі) синхронні. X і Y - це два потоки або два процеси або одна нитка або один процес? ми не знаємо.
4) асинхронний: перш ніж Y відповість X, X залишає там і X може виконувати інші завдання. X не повернеться, поки Y не зателефонує йому. Тепер ми кажемо: X і Y (два модулі) асинхронні. X і Y - це два потоки або два процеси або один процес? ми не знаємо. Але ми впевнені, що X і Y не могли бути однією ниткою.
Будь ласка, зверніть увагу на два жирних речення вище. Чому жирне речення у 2) містить два випадки, тоді як жирне речення у 4) містить лише один випадок? Це є ключовою різницею між неблокуючим та асинхронним.
Ось типовий приклад про незаблокування та синхронність:
// thread X
while (true)
{
msg = recv(Y, NON_BLOCKING_FLAG);
if (msg is not empty)
{
break;
}
sleep(2000); // 2 sec
}
// thread Y
// prepare the book for X
send(X, book);
Ви можете бачити, що ця конструкція не блокує (ви можете сказати, що більшість часу цей цикл робить щось безглузде, але в очах процесора X працює, це означає, що X не блокує), тоді як X і Y є синхронними, оскільки X може не продовжуйте робити будь-які інші речі (X не може вистрибнути з циклу), поки не отримає книгу від Y.
Зазвичай в цьому випадку зробити блокування X набагато краще, оскільки неблокуючи витрачає багато ресурсів для дурного циклу. Але цей приклад хороший, щоб допомогти вам зрозуміти факт: неблокування не означає асинхронність.
Чотири слова змушують нас легко плутати, що ми повинні пам’ятати, що ці чотири слова служать для дизайну архітектури. Дізнатися про те, як створити хорошу архітектуру - це єдиний спосіб їх розрізнити.
Наприклад, ми можемо розробити такий тип архітектури:
// Module X = Module X1 + Module X2
// Module X1
while (true)
{
msg = recv(many_other_modules, NON_BLOCKING_FLAG);
if (msg is not null)
{
if (msg == "done")
{
break;
}
// create a thread to process msg
}
sleep(2000); // 2 sec
}
// Module X2
broadcast("I got the book from Y");
// Module Y
// prepare the book for X
send(X, book);
У прикладі тут ми можемо сказати це
Якщо вам потрібно, ви також можете описати ці теми, створені в X1, чотирма словами.
Більш важливі речі: коли ми використовуємо синхронні замість асинхронних? коли ми використовуємо блокування замість блокування?
Чому Nginx не блокує? Чому Apache блокується?
Щоб зробити хороший вибір, ви повинні проаналізувати свої потреби та перевірити працездатність різних архітектур. Не існує такої архітектури, яка підходила б для різних потреб.
Ставлячи це питання в контексті NIO та NIO.2 в java 7, async IO є на один крок більш досконалим, ніж неблокуючий. Якщо не блокує дзвінки Java NIO, ви можете встановити всі канали (SocketChannel, ServerSocketChannel, FileChannel тощо) як такі AbstractSelectableChannel.configureBlocking(false)
. Після повернення цих викликів вводу-виводу, однак, вам, швидше за все, потрібно буде контролювати чеки, такі як, якщо і коли читати / писати знову та ін.
Наприклад,
while (!isDataEnough()) {
socketchannel.read(inputBuffer);
// do something else and then read again
}
За допомогою асинхронної api в java 7 ці елементи керування можна зробити більш універсальними. Один з 2 способів - це використання CompletionHandler
. Зауважте, що обидва read
дзвінки не блокують.
asyncsocket.read(inputBuffer, 60, TimeUnit.SECONDS /* 60 secs for timeout */,
new CompletionHandler<Integer, Object>() {
public void completed(Integer result, Object attachment) {...}
public void failed(Throwable e, Object attachment) {...}
}
}
FileChannel
не вибирається і не може бути налаштований на неблокування.
Як ви, мабуть, бачите з безлічі різних (і часто взаємовиключних) відповідей, це залежить від того, кого ви запитуєте. На деяких аренах терміни є синонімами. Або кожен може посилатися на два подібних поняття:
У будь-якому випадку, намір полягає в тому, щоб дозволити програмі не блокувати очікування повільного завершення процесу - те, як очікується, що програма реагує, є єдиною реальною різницею. Який термін позначає, який також змінюється від програміста до програміста, від мови до мови або від платформи до платформи. Або терміни можуть стосуватися абсолютно різних понять (наприклад, використання синхронного / асинхронного по відношенню до потокового програмування).
Вибачте, але я не вірю, що існує одна правильна відповідь, яка є правдою в усьому світі.
А Неблокована виклик повертається відразу з будь-якими даними доступні: повне число байтів не потрібно, менше, або взагалі.
Асинхронний виклик запитує передачу , яка буде виконуватися в усій своїй повноті () , але буде завершена в якій - то момент в майбутньому.
Неблокуючий: Ця функція не буде чекати, поки знаходиться у стеці.
Асинхронний: робота може продовжуватися від імені виклику функції після того, як цей виклик залишив стек
Синхронність визначається як те, що відбувається одночасно.
Асинхронність визначається як не відбувається одночасно.
Саме це викликає першу плутанину. Синхронність - це насправді те, що називають паралельним. Поки асинхронність послідовна, зробіть це, тоді зробіть це.
Тепер вся проблема полягає в моделюванні асинхронної поведінки, оскільки вам потрібна деяка операція, яка потребує реакції іншого, перш ніж вона може початися. Таким чином, це проблема координації, як ви дізнаєтесь, що тепер можете розпочати цю операцію?
Найпростіше рішення відоме як блокування.
Блокування - це коли ви просто вирішили чекати, коли буде зроблено інше, і повернуть вам відповідь, перш ніж перейти до операції, яка цього потребувала.
Тож якщо вам потрібно покласти масло на тості, і, таким чином, спочатку потрібно підсмажити розведене. Спосіб їх узгодження полягає в тому, що ви спершу тостуйте розведених, а потім нескінченно дивитесь на тостер, поки він не спливе тост, а потім продовжуєте наносити на них масло.
Це найпростіше рішення і працює дуже добре. Немає жодної реальної причини не використовувати його, якщо у вас трапляються також інші речі, які вам потрібно робити, які не потребують узгодження з операціями. Наприклад, роблячи деякі страви. Навіщо чекати простою, дивлячись на тостер постійно, щоб тост вискочив, коли ви знаєте, що це забирає трохи часу, і ви могли випрати цілий посуд, поки він закінчиться?
Ось тут вступають у дію два інші рішення, відомі відповідно як неблокуючі та асинхронні.
Неблокування - це коли ви вирішите робити інші непов'язані речі, поки ви чекаєте операції. Перевірка наявності відповіді, як вважаєте за потрібне.
Тож замість того, щоб дивитись на тостер, щоб він вискочив. Ти йдеш і миєш цілу посуд. А потім ви заглядаєте в тостер, щоб побачити, чи тости вискочили. Якщо їх немає, ви йдете мити іншу посуд, перевіряючи тостер між кожною посудом. Коли ви бачите, що тости спливали, ви перестаєте мити посуд, а замість цього берете тост і переходите до того, щоб покласти на них масло.
Постійно перевіряти тости може прикро, хоча, уявіть, тостер знаходиться в іншій кімнаті. Між посудом ви витрачаєте час, їдучи до тієї іншої кімнати, щоб перевірити тост.
Тут йде асинхронність.
Асинхронний - це коли ви вирішите робити інші непов'язані речі, поки ви чекаєте операції. Замість того, щоб перевірити це, ви делегуєте роботу перевірки на щось інше, це може бути сама операція або спостерігач, і ви маєте про це сповістити і, можливо, переплутати вас, коли відповідь буде доступною, щоб ви могли перейти до іншої операції, яка це було потрібно.
Це дивна термінологія. Це не має великого сенсу, оскільки всі ці рішення - це способи створення асинхронної координації залежних завдань. Тому я вважаю за краще називати це парним.
Тож для цього ви вирішили оновити тостер, щоб він подав звукові сигнали, коли закінчуються тости. Ви трапляєтеся, що постійно слухаєте, навіть якщо миєте посуд. Почувши звуковий сигнал, ви в черзі запам'яталися, що як тільки ви закінчите мити поточну страву, ви зупинитесь і підете покласти масло на тост. Або ви могли б перервати миття поточного блюда і негайно розібратися з тостом.
Якщо у вас виникли проблеми з прослуховуванням звукового сигналу, ви можете змусити свого партнера спостерігати за тостером для вас, і приходьте, коли вам підкажуть тост. Ваш партнер може сам вибрати будь-яку з перерахованих вище трьох стратегій, щоб узгодити своє завдання дивитися тостер і розповідати, коли вони будуть готові.
На завершення, добре розуміти, що хоча не блокування та асинхронізація (або те, що я вважаю за краще називати парним) дозволяють вам робити інші речі, поки ви чекаєте, у вас теж немає. Ви можете постійно фіксувати перевірку стану виклику, що не блокує, нічого більше не роблячи. Це часто гірше, ніж блокування, хоча (наприклад, дивлячись на тостер, потім вдалину, потім повертаючи його до тих пір, поки не буде зроблено), тому багато API, що не блокують, дозволяють перейти з режиму блокування з нього. Навіть ви можете чекати простою, поки не отримаєте сповіщення. Мінусом у цьому випадку є те, що додавання сповіщення було складним та потенційно дорогим для початку. Вам довелося придбати новий тостер з функцією звукового сигналу або переконати свого партнера спостерігати за ним.
І ще одне - вам потрібно усвідомити компроміси, які всі три забезпечують. Один явно не кращий за інших. Подумайте на моєму прикладі. Якщо ваш тостер настільки швидкий, ви не встигнете випрати посуд, навіть не почнете її мити, так швидко ваш тостер. Почати щось у цьому випадку - це лише марна трата часу та сил. Блокування буде робити. Так само, якщо миття посуду займе в 10 разів більше часу, ніж тост. Ви повинні запитати себе, що важливіше зробити? Тост може наступити холодно і важко до того часу, не варто, блокування також зробиться. Або вам слід підбирати швидші речі, поки ви чекаєте. Існує більш очевидно, але моя відповідь вже досить довгий, моя думка полягає в тому, що вам потрібно подумати над усім цим, і над складностями впровадження кожного, щоб вирішити, чи варто його, і чи це '
Редагувати:
Незважаючи на те, що це вже давно, я також хочу, щоб це було повно, тому я додам ще два бали.
1) Також зазвичай існує четверта модель, відома як мультиплексована . Це коли ви чекаєте одного завдання, ви починаєте інше, і поки ви чекаєте обох, ви запускаєте ще одне і так далі, поки у вас не буде розпочато багато завдань, а потім ви очікуєте простою, але на всіх їх. Отже, як тільки це буде зроблено, ви можете перейти до обробки його відповіді, а потім повернутися до очікування інших. Він відомий як мультиплексований, тому що, поки ви чекаєте, вам потрібно перевіряти кожне завдання одне за іншим, щоб побачити, чи вони виконані, ad vitam, поки одна не буде. Це трохи розширення поверх звичайного не блокування.
У нашому прикладі це було б як запустити тостер, потім посудомийну машину, потім мікрохвильову піч тощо. А потім чекати на будь-яку з них. Де ви б перевірили тостер, щоб побачити, чи зроблено це, якщо ні, ви знову перевірите посудомийну машину, якщо ні, мікрохвильову піч тощо.
2) Незважаючи на те, що я вважаю це великою помилкою, синхронність часто використовується для позначення одних речей. І асинхронно багато речей одночасно. Таким чином, ви побачите синхронне блокування та неблокування, яке використовується для позначення блокування та неблокування. І асинхронне блокування та неблокування, яке використовується для позначення мультиплексованих і парних.
Я не дуже розумію, як ми туди потрапили. Але якщо мова йде про IO та Computation, синхронні та асинхронні часто посилаються на те, що краще відомо як «неперекрите» та «перекрите». Тобто, асинхронність означає, що IO та обчислення перекриваються, так само, що відбуваються одночасно. У той час як синхронних засобів їх немає, таким чином відбувається послідовно. Для синхронного неблокування це означатиме, що ви не запускаєте інший IO або Computation, ви просто зайняті в очікуванні та імітуєте виклик блокування. Я б хотів, щоб люди перестали зловживати подібними синхронними та асинхронними. Тож я не заохочую це.
Блокування виклику: управління повертається лише тоді, коли виклик завершується.
Неблокуючий виклик: керування повертається негайно. Пізніше ОС якось повідомляє процес, що виклик завершено.
Синхронна програма: програма, яка використовує блокування дзвінків. Щоб не замерзнути під час виклику, у нього повинно бути 2 або більше потоку (саме тому він називається Synchronous - потоки працюють синхронно).
Асинхронна програма: програма, яка використовує не блокуючі дзвінки. Він може мати лише 1 потік і все ще залишатися інтерактивним.
Вони відрізняються лише правописом. Немає різниці в тому, на що вони посилаються. Щоб бути технічним, можна сказати, що вони різняться між собою. Неблокування посилається на контрольний потік (він не блокується.) Асинхронний посилається на обробку даних події \ (не синхронно.)
Моделі, що блокують, вимагають, щоб програма ініціювання блокувалась після запуску вводу-виводу Це означає, що не можна одночасно перекривати обробку та введення / виведення. Синхронна модель, що не блокує, дозволяє перекривати обробку та введення-виведення, але вона вимагає, щоб програма перевіряла стан вводу-виводу на періодичній основі. Це залишає асинхронний неблокуючий введення / виведення, що дозволяє перекривати обробку та введення / виведення, включаючи повідомлення про завершення вводу / виводу.
Блокування: контроль повертається до виклику прецесії після завершення обробки примітиву (синхронізації чи асинхронізації)
Не блокуючи: контроль повертається до процесу одразу після виклику