Конкретные примеры
Я хотел бы добавить несколько реальных примеров и соединить их с миром разработки программного обеспечения. Во-первых, подумайте над тем, что, как я надеюсь, соответствует вашему интуитивному определению «синхронный»: мигание светлячков при некоторых обстоятельствах. Во- вторых, рассмотрим релейный олимпийский 4х100 женщин гонки . В-третьих, подумайте над тем старым следом из военных фильмов: «Мужчины, синхронизируйте свои часы!»
Теперь давайте подумаем о том, что происходит. Давайте начнем с наблюдения, что все эти вещи являются процессами или сущностями, расширенными во времени . Нет смысла говорить, что чаша "синхронная", а камень "асинхронный". Во-вторых, для танго нужны двое . Вы не можете сказать, что «бегун синхронизирован». Синхронизировать с чем? Наконец, чтобы два процесса могли что-то делать одновременно, если они уже не имеют одинаковую частоту и фазу, один или оба из них должны ждать .
Анализ
Когда в словарном определении говорится, что две сущности синхронизированы «возникают или существуют одновременно», это очень хорошо согласуется с концепцией света от светлячков. К сожалению, говорить, что свет «синхронизирован», - это неаккуратный способ сказать, что процессы освещения светлячка синхронизированы.
Итак, как может группа светлячков, у которых, по-видимому, нет Apple SmartWatch и NTP, чтобы управлять ими, может одновременно прошить свои задние части? Что ж, это довольно легко, если у них есть возможность установить постоянный темп и внести небольшие изменения в него. Они просто мигают, и если сразу после них мигает больше людей, они замедляются (увеличивают задержку), тогда как, если больше вспышек прямо перед ними, они ускоряются (уменьшают задержку). Таким образом, они могут использовать простой процесс обратной связи для достижения практически одинакового темпа и фазы. Здесь важно отметить, что они достигают синхронности, ожидая подходящего момента, чтобы вспыхнуть .
Гонка 4х100 интересна тем, что вы видите обе формы хронометража процесса в действии: бегуны внутри команды синхронизируются, а бегуны в разных командах «асинхронны». Второй участник в реле должен дождаться, пока первый участник войдет в зону передачи . Передача - это синхронное событие между этими двумя бегунами. Тем не менее, бегуны на разных дорожках не заботятся о том, что происходит на другой дорожке , и, скорее всего, не замедляются и не выполняют синхронизацию самостоятельно. Каждая дорожка бегунов асинхронна по отношению друг к другу. Опять же, мы видим, что синхронизация влечет за собой ожидание, а асинхронность - нет.
Наконец, солдаты в компании (взвод, пожарной команды и т.д.) должны синхронизировать свои часы , чтобы они могли атаковать противника одновременно . Возможно, некоторые солдаты прибывают на свои позиции раньше других или имеют возможность стрелять по врагу раньше. Но одновременная атака, как правило, более эффективна, чем случайная атака из-за элемента неожиданности. Таким образом, чтобы достичь синхронности, многие солдаты должны ждать назначенного времени, чтобы действовать.
Определяющая особенность
Почему этот акцент на ожидании? Ну, это потому, что ожидание является определяющим признаком, который отличает синхронные от асинхронных процессов. Если у вас есть два процесса, о которых вы ничего не знаете, по умолчанию вы должны предположить, что они асинхронные. Например, доставка посылки и проезд машины скорой помощи, скорее всего, не синхронизированы. Чтобы продемонстрировать, что два процесса фактически синхронизированы, вам нужно найти особый момент времени: точку синхронизации .
Водитель, доставляющий посылку, и скорая помощь, доставляющая кого-то в больницу, обычно не разделяют какие-либо моменты времени, которые мы определяем как «точку синхронизации». С другой стороны, светлячки, мигающие в унисон, имеют точку синхронизации каждый раз, когда они мигают, ретрансляторы имеют точку синхронизации каждый раз, когда они передают эстафету, а солдаты имеют точку синхронизации, когда они начинают свою атаку. Если вы можете идентифицировать одну или несколько точек синхронизации, то процессы синхронизируются . Это должно быть легко понять, потому что «syn-» - это греческий префикс, означающий «с» или «вместе», а «chrono» - греческий корень «времени». «Синхронизированный» буквально означает «одновременно»,
границы
Обратите внимание, что «синхронизация» не обязательно применяется ко всему времени жизни одного или обоих процессов. Я бы сказал, что это относится только к «времени ожидания до и включая точки (точки) синхронизации». Таким образом, два процесса могут работать асинхронно до тех пор, пока они не достигнут состояния, в котором им нужно общаться, затем они синхронизируются, обмениваются информацией и после этого продолжают асинхронно. Простой пример - встреча с кем-то за кофе. Очевидно, что встреча является точкой синхронизации (или, скорее, многими), и тот факт, что два человека прибывают в эту точку, демонстрирует синхронность. Однако мы бы не сказали, что из-за того, что два человека встретились за кофе, эти две человеческие жизни"синхронизированы". Возможно, это был единственный момент в их жизни, который они встретили, и все остальное, что они делают, в остальном является независимым.
Это также не тот случай, когда случайные встречи демонстрируют синхронность. Если два незнакомца передают друг друга на улице, то факт, что они в какое-то время находятся в определенном месте, не является синхронным. Не факт, что один человек сидит на скамейке в ожидании автобуса, а другой случайно проходит мимо. Процессы синхронны только тогда, когда они встречаются с определенной целью .
Подключение программного обеспечения
Теперь давайте подумаем об очень фундаментальной задаче в программном обеспечении: чтение из файла. Как вы, вероятно, знаете, запоминающее устройство обычно в тысячи-миллионы раз медленнее, чем кеш или основная память. По этой причине операционные системы и библиотеки языков программирования обычно предлагают как синхронные, так и асинхронные операции ввода-вывода. Теперь, даже если ваша программа имеет только один поток, вы должны думать об ОС как о «отдельном процессе» для целей этого обсуждения.
Синхронизация
Когда вы выполняете «синхронное чтение ввода-вывода», ваш поток должен ждать, пока данные не станут доступны, после чего они продолжатся. Это очень похоже на эстафету, передающую эстафету следующему, но вместо этого представьте себе эстафету, в которой только два бегуна проходят по трассе, а второй бегун также отдает назад первому.
В этом случае поток вашей программы и процесс ввода-вывода ОС не «происходят (действуют) одновременно», и поэтому странно говорить, что эти процессы «синхронизированы». Но это неправильный взгляд на это! Это все равно что сказать: «Бегуны в эстафетной команде не бегут одновременно, поэтому они не синхронизируются». На самом деле оба утверждения неверны! Бегуны в эстафетной команде делают и должны бежать в одно и то же время, но только в очень специфический момент: передача эстафеты. Фактически, только этот особенный момент во время гонки убеждает нас в том, что эстафетные команды синхронизированы для начала! Если мы рассматриваем запрос и ответ ввода-вывода как «жезл»,
С другой стороны, если мы подумаем о чем-то вроде анализа методом конечных элементов на суперкомпьютере, мы увидим, что тысячи процессов должны работать в режиме блокировки, чтобы обновить огромное глобальное состояние. Даже если некоторые узлы завершают свою работу за заданный временной шаг раньше других, им всем нужно ждать завершения временного шага, потому что результаты распространяются на соседей в пространстве. Этот вид синхронизации похож на светлячков: все актеры выполняют одно и то же задание.
Разнообразие процессов
По этой причине мы можем придумать несколько терминов, чтобы помочь нам понять, что происходит три вида вещей: «однородная синхронность», «гетерогенная синхрония» и «последовательная синхронность». Поэтому, когда актеры выполняют одну и ту же задачу одновременно (ВЭД, светлячки), они «однородны». Когда они выполняют разные задачи одновременно (солдаты бегут против ползания или плывут к месту назначения, физика против звука против потоков ИИ в игре), они «неоднородны». Когда они выполняют задачи по одному, они являются «последовательными» (реле бегуны, блокировка ввода / вывода). Они могут выглядеть очень по-разному, но у них есть одно важное свойство: все типы актеров выполняют некоторое ожидание, чтобы гарантировать, что все прибудут в точку синхронизации одновременно. между точками синхронизации или «выполнение одного и того же действия» не имеет отношения к свойству синхронности.
Конвейеры рендеринга в GPU являются синхронными, потому что все они должны завершить кадр вместе и начать новый кадр вместе. Они однородны, потому что выполняют одинаковую работу, и все они активны вместе. Но основной игровой цикл сервера и блокирующие потоки ввода / вывода, которые обрабатывают удаленный ввод, неоднородны, потому что они выполняют очень разные виды работы, а некоторые из потоков ввода / вывода вообще ничего не будут делать, потому что не все соединения используются. Несмотря на это, они синхронизированы, потому что они должны совместно использовать состояние атома (игрок не должен видеть частичное обновление игрового мира, а сервер не должен видеть только фрагмент ввода игрока).
асинхронный
Теперь давайте рассмотрим «асинхронное чтение ввода / вывода». Когда ваша программа отправляет запрос в ОС для чтения части данных из хранилища, вызов немедленно возвращается . Давайте проигнорируем обратные вызовы и сосредоточимся на опросе. В общем, момент, когда данные доступны вашей программе, не соответствует ни одному особому моменту времени, когда речь идет о потоке вашей программы. Если ваша программа явно не ожидает данных, то поток даже не будет точно знать, когда наступит этот момент. Он только обнаружит, что данные ожидают при следующей проверке.
Нет особого времени встречи, когда ОС и программный поток соглашаются передать данные. Они как два корабля, проходящих ночью. Асинхронность характеризуется отсутствием ожидания, Конечно, поток программы часто в конечном итоге будет ждать операции ввода-вывода, но это не нужно. Он может с радостью продолжать выполнять другие вычисления, пока происходит выборка ввода-вывода, и проверять это позже, только когда у него есть запасной момент. Конечно, как только ОС закончит извлекать данные, она тоже не будет ждать. Он просто размещает данные в удобном месте и рассказывает о своем бизнесе. В этом случае это похоже на то, что программа передает эстафету ОС, а ОС приходит позже, сбрасывает эстафету на землю вместе с данными и уходит с дорожки. Программа может или не может ждать, чтобы получить передачу.
параллелизм
Когда мы помечаем функцию как «асинхронную» в программном обеспечении, это часто означает, что мы хотим параллелизма . Но помните, что параллелизм не подразумевает синхронность . Светлячки являются хорошим примером, потому что они тоже демонстрируют как синхронное, так и асинхронное поведение. В то время как большинство мух вспыхнуло в унисон, многие явно не согласились с остальной частью группы и вспыхнули более случайно. Мухи могли действовать одновременно , но не все они были синхронизированы .
Теперь, когда мы помечаем некоторый код как «асинхронный», это выглядит забавно, потому что это подразумевает, что остальной код, не помеченный как «синхронизированный». Что это вообще значит? Разве мы не настаивали на том, что для «синхронизации» нужны два танго? Но что, если мы говорим о выполнении кода в одном потоке? В этом случае нам нужно сделать шаг назад и представить программу как последовательность состояний и переходов между этими состояниями. Оператор в программе вызывает переход состояния. Мы можем думать об этом как о «микропроцессе», который начинается и заканчивается заявлением. Точки последовательности, определяемые языком, фактически являются точками синхронизации этих «микропроцессов». И, таким образом, мы можем просматривать однопоточные,
Целостность языка программирования гарантирует, что обновления состояний не будут влиять на операторы, а точки последовательности определяют границы, через которые компилятору не разрешается проводить заметные оптимизации. Например, порядок вычисления выражений в операторе может быть неопределенным или недоопределенным, что дает компилятору свободу оптимизировать оператор различными способами. Но к тому времени, когда начинается следующее утверждение, программа должна быть в четко определенном состоянии, если сам PL является исправным.
К настоящему времени должно быть ясно, что мы подразумеваем под «асинхронностью». Это точно означает, что подразумеваемый контракт синхронности в блоке кода освобождается для асинхронного блока. Разрешается обновлять состояние программы независимо, без гарантий безопасности, обычно подразумеваемых последовательной (практически последовательной, синхронной) моделью вычислений. Конечно, это означает, что мы должны быть особенно внимательны, чтобы не нарушать состояние программы с несогласованностью. Обычно это означает, что мы вводим ограниченную явную синхронность для координации с асинхронным блоком. Обратите внимание, что это означает, что асинхронный блок может быть как асинхронным, так и синхронным в разное время! Но напоминая, что синхронизация просто указывает на существование точки синхронизации, у нас не должно возникнуть проблем с принятием этого понятия.