Конкретні приклади
Я хотів би додати кілька реальних прикладів та підключити їх до світу інженерії програмного забезпечення. По-перше, подумайте про те, що, сподіваюся, відповідає вашому інтуїтивному визначенню "синхронного": спалахування світлячків за певних обставин. По- друге, розглянемо релейний олімпійський 4х100 жінок гонки . По-третє, вважайте, що стара трупа з військових фільмів: "Чоловіки, синхронізуйте годинник!"
Тепер давайте подумаємо, що відбувається. Для початку почнемо, спостерігаючи, що всі ці речі - це процеси або сутності, розширені в часі . Немає сенсу говорити, що чаша "синхронна", а рок - "асинхронний". По-друге, на танго потрібно два . Ви не можете сказати, що "бігун синхронізується". Синхронізувати з чим? Нарешті, для того, щоб два процеси одночасно могли робити щось, якщо вони вже не мають точно однакової частоти та фази, один або обидва повинні почекати .
Аналіз
Коли в словниковому визначенні сказано, що два об'єкти синхронізуються "виникають або існують одночасно", це дуже добре узгоджується з поняттям світла від світлячків. На жаль, сказати, що світло "синхронізоване" - це неохайний спосіб сказати, що процеси освітлення світлячків синхронізовані.
То як же куля світлячків, які, мабуть, не мають Apple SmartWatch та NTP, щоб керувати ними, встигнути одночасно спалахнути задніми кінцями? Ну, це досить просто, якщо вони мають засоби для встановлення послідовного темпу і можуть внести невеликі корективи в нього. Вони просто спалахують, і якщо більше людей спалахує відразу після них, вони сповільнюються (збільшують затримку), тоді як якщо більше спалахує прямо перед ними, вони прискорюються (зменшують затримку). Таким чином, вони можуть використовувати простий процес зворотного зв'язку, щоб досягти фактично однакового темпу та фази. Тут важливим є зауваження, що вони досягають синхронності, чекаючи, коли потрібний момент спалахне .
Гонка 4x100 цікава тим, що ви бачите обидві форми хронометражу процесу: бігуни в команді синхронізовані, а бігуни в різних командах "асинхронізовані". Другий бігун в естафеті повинен чекати, поки перший бігун потрапить у зону передачі . Передача - це синхронна подія між цими двома бігунами. Однак бігунів на різних смугах все одно, що відбувається на іншій смузі , і, звичайно, не сповільнюються і синхронізуються. Кожна смуга бігунів асинхронна відносно один одного. Знову ми бачимо, що синхронізація тягне за собою очікування, а асинхронність - ні.
Нарешті, солдати в компанії (взвод, пожежної команди і т.д.) повинні синхронізувати свій годинник , щоб вони могли атакувати противника одночасно . Можливо, деякі солдати приходять на свої позиції перед іншими, або мають можливість швидше обстрілювати ворога. Але одночасний напад, як правило, є більш ефективним, ніж випадковий напад через стилю здивування. Отже, щоб досягти синхронності, багатьом солдатам необхідно чекати призначеного часу для дії.
Визначення функції
Чому саме цей акцент на очікуванні? Ну, це тому, що очікування - визначальна особливість, яка відрізняє синхронність від асинхронних процесів. Якщо у вас є два процеси, про які ви нічого не знаєте, вам слід за замовчуванням припустити, що вони асинхронні. Наприклад, доставка пакетів та швидка допомога, швидше за все, не синхронізовані. Для того, щоб продемонструвати, що два процеси насправді синхронізовані, вам потрібно знайти дуже особливий момент часу: точку синхронізації .
Водій доставки, що скидає пакет, і швидка допомога, яка їде до лікарні, зазвичай не поділяють жодного моменту часу, який ми ідентифікуємо як "пункт синхронізації". З іншого боку, світлячки, що миготять в унісон, мають точку синхронізації кожного разу, коли вони спалахують, бігуни-естафети мають точку синхронізації кожного разу, коли передають естафету, а солдати мають точку синхронізації, коли вони розпочинають свою атаку. Якщо ви можете ідентифікувати одну або кілька точок синхронізації, то процеси синхронізуються . Це має бути легко зрозуміти, оскільки "син-" - це грецький префікс, що означає "з" або "разом", а "хроно" - грецький корінь для "часу". "Синхронізований" буквально означає "одночасно",
Межі
Зауважте, що "синхронізація" не обов'язково поширюється на весь час роботи одного або обох процесів. Я заперечую, що це стосується лише "часу очікування до та включаючи точки синхронізації". Таким чином, два процеси можуть функціонувати асинхронно, поки не досягнуть стану, коли їм потрібно спілкуватися, потім вони синхронізуються, обмінюються інформацією, а потім продовжують асинхронно. Простий приклад - зустрітися з кимось за кавою. Очевидно, що зустріч - це пункт синхронізації (або багато, скоріше), і той факт, що до цього пункту приїжджають двоє людей, демонструє синхронність. Однак ми б не сказали, що через те, що дві людини зустрілися за кавою, ці два людські життя"синхронізовані". Можливо, це був єдиний момент у їхньому житті, який вони зустріли, а все інше, що вони роблять, - інакше незалежне.
Не випадково випадкові зустрічі демонструють синхронність. Якщо двоє незнайомих людей проходять один на одного на вулиці, той факт, що вони перебувають у певному місці певний час, не доводить синхронності. Не факт також, що одна людина сидить на лавці, чекаючи автобуса, а інша, буває, проходить повз. Процеси синхронні лише тоді, коли вони зустрічаються з певною метою .
Підключення до програмного забезпечення
Тепер давайте подумаємо про дуже фундаментальне завдання програмного забезпечення: читання з файлу. Як ви, напевно, знаєте, масове зберігання зазвичай в тисячі-мільйони разів повільніше, ніж кеш або основна пам'ять. З цієї причини операційні системи та бібліотеки мов програмування зазвичай пропонують як синхронні, так і асинхронні операції вводу / виводу. Тепер, навіть якщо у вашій програмі є лише одна нитка, для цілей цієї дискусії слід вважати, що ОС є "окремим процесом".
Синхронізація
Коли ви робите "синхронне зчитування вводу / виводу", ваш потік повинен зачекати, поки дані стануть доступними, і в цей момент він продовжується. Це дуже схоже на естафету, який передає естафету наступному бігуну, але уявіть замість цього естафету з двома бігунами, які проходять всю дорогу навколо траси, а другий бігун також відступає назад до першого.
У цьому випадку ваш програмний потік та процес введення / виводу ОС не "відбуваються (діють) одночасно", і тому дивно говорити, що ці процеси "синхронізовані". Але це неправильний погляд на це! Це як сказати: "Бігуни в естафетній команді не працюють одночасно, тому вони не синхронізуються". Насправді обидва твердження помилкові! Бігуни в естафетній команді роблять і повинні бігати одночасно, але тільки в дуже конкретний момент: передача естафети. Насправді, саме цей особливий момент під час гонки переконує нас, що естафетні команди синхронізуються для початку! Якщо ми розглядаємо запит і відповідь вводу / виводу як "естафету",
З іншого боку, якщо ми думаємо про щось на кшталт аналізу кінцевих елементів на суперкомп'ютері, ми бачимо, що тисячі процесів повинні працювати в режимі блокування, щоб оновити масовий глобальний стан. Навіть якщо деякі вузли завершують свою роботу за певний часовий крок перед іншими, всі вони повинні дочекатися завершення кроку часу, оскільки результати поширюються на сусідів через простір. Цей вид синхронізації схожий на світлячків: усі актори виконують однакові завдання.
Різноманітність процесу
З цієї причини ми можемо винайти кілька термінів, які допоможуть нам побачити, що триває три речі: "однорідна синхронія", "неоднорідна синхронія" та "послідовна синхронія". Тож коли актори виконують одне і те ж завдання одночасно (FEA, світлячки), вони «однорідні». Коли вони виконують різні завдання одночасно (солдати, які бігають проти повзання та плавання до місця призначення, фізика проти звуку проти AI-потоків у грі), вони "неоднорідні". Коли вони виконують завдання по черзі, вони є "послідовними" (естафети, блокуючи введення-виведення). Вони можуть виглядати дуже по-різному, але вони мають одне суттєве властивість: всі типи акторів виконують певні очікування, щоб усі прийшли в точку синхронізації одночасно. між точками синхронізації, або "виконання тієї ж дії" не має значення властивості синхронізації.
Трубопроводи візуалізації в графічному процесорі синхронізовані, оскільки всі вони повинні закінчувати кадр разом і починати новий кадр разом. Вони однорідні, тому що роблять однакові роботи, і всі вони разом активні. Але основна ігровий цикл сервера та блокуючі потоки вводу / виводу, які обробляють віддалений вхід, неоднорідні, оскільки вони виконують дуже різні види роботи, а деякі потоки вводу / виводу взагалі нічого не роблять, тому що не всі використовуються з'єднання. Незважаючи на це, вони синхронізовані, тому що вони повинні мати загальний стан атоми (гравець не повинен бачити часткового оновлення світу ігор, а також сервер не повинен бачити лише фрагмент введення гравця).
Асинхронізація
Тепер розглянемо "читання асинхронічного вводу / виводу". Коли ваша програма надсилає запит в ОС, щоб прочитати трохи даних із сховища, виклик негайно повертається . Давайте ігноруємо зворотні дзвінки та зосередимось на опитуванні. Загалом, момент, коли дані доступні для вашої програми, не відповідає жодному спеціальному моменту часу, що стосується потоку вашої програми. Якщо ваша програма явно не чекає даних, то потік навіть не буде точно знати, коли настає цей момент. Він виявить лише, що дані чекають наступного разу, коли вони перевірять.
Немає спеціального часу зустрічі, коли ОС і програмний потік погоджуються передавати дані. Вони як два кораблі, що проходять у ніч. Асинхронність характеризується цією відсутністю очікування. Звичайно, програмний потік часто закінчує очікування операції вводу / виводу, але цього не потрібно. Він може із задоволенням продовжувати робити інші обчислення, поки відбувається виведення вводу / виводу, і перевіряти лише пізніше, коли у нього є запасний момент. Звичайно, щойно ОС працює за отриманням даних, вона теж не сидить навколо очікування. Він просто розміщує дані десь зручно і продовжує свою справу. У цьому випадку це все одно, що програма передає естафету ОС, а ОС з'являється пізніше, опускає естафету на землю разом із даними та виходить зі сліду. Програма може або не може чекати, щоб отримати роздачу.
Паралелізм
Коли ми позначаємо функцію як "асинхронізацію" в програмному забезпеченні, це часто означає, що ми хочемо паралелізму . Але пам’ятайте, що паралелізм не передбачає синхронності . Світлячки - хороший приклад, тому що вони теж виявляють як синхронну, так і асинхронну поведінку. У той час як більшість мух блимали в унісон, багато хто, очевидно, не відповідали решті групи і блиснули більше випадково. Мухи, можливо, діяли одночасно , але вони були не всі синхронізовані .
Тепер, коли ми позначаємо якийсь код як "асинхронний", він виглядає смішно, оскільки це означає, що решта коду, не так позначеного, є "синхронізація". Що це навіть означає? Хіба ми не наполягали на тому, що для сингонізації потрібно два для танго? Але що робити, якщо ми говоримо про виконання коду в одному потоці? У цьому випадку нам потрібно зробити крок назад і продумати програму як послідовність станів і переходів між цими станами. Заява в програмі викликає перехід стану. Ми можемо вважати це як "мікропроцес", який починається і припиняється з твердженням. Точки послідовності, визначені мовою, насправді є точками синхронізації цих "мікропроцесів". Таким чином, ми можемо переглянути однопотокові,
Цілісність мови програмування гарантує, що оновлення стану не перешкоджають операторам, а точки послідовності визначають межі, через які компілятору не дозволяється робити оптимізації, що спостерігаються. Наприклад, порядок оцінки виразів у висловлюванні може бути невизначеним або недоозначеним, що дає компілятору свободу оптимізувати висловлювання різними способами. Але до початку наступного твердження програма повинна бути в чітко визначеному стані, якщо ПЛ сам по собі звучить.
На сьогоднішній день має бути зрозуміло, що ми маємо на увазі під «асинхронією». Це означає саме те, що мається на увазі контракт синхронії в блоці коду вилучається для блоку асинхронізації. Дозволяється оновлювати стан програми самостійно, без гарантій безпеки, як правило, мається на увазі послідовна (послідовна, синхронна) модель обчислення. Звичайно, це означає, що нам потрібно бути особливо обережними, щоб ми не руйнували стан програми з непослідовністю. Зазвичай це означає, що ми вводимо обмежену, явну синхронність для координації з блоком асинхронізації. Зауважте, що це означає, що блок асинхронізації може бути як асинхронним, так і синхронним у різний час! Але нагадуючи, що синхронізація лише вказує на існування точки синхронізації, у нас не повинно виникнути проблем з прийняттям цього поняття.