Обзор синхронизации и асинхронности по аналогии с повседневными делами…

В информатике нам нравится запускать программы. Мы пишем строки кода, которые принимают какие-то входные данные, передают их набору шестерен для вычислений и выдают результат. Вряд ли это новость. Но что поначалу непонятно, когда вы обучаетесь программисту, так это вся сложность, которую скрывает это предложение. Чтобы лучше понять это, давайте поговорим о мытье посуды, покупках и походах в прачечную…

Примечание: все иллюстрации сделаны автором.

В последнее время мне приходилось много думать об этом на работе. Мы столкнулись с вопросом «безопасность против скорости». Точнее: скажем, у вас есть фрагмент кода, который может прийти откуда угодно — тогда вы должны просто запустить его и надеяться на лучшее? или вам следует вместо этого внедрить меры предосторожности, чтобы он не сломал ваш компьютер, не стер все ваши файлы или просто не дал сбой и остался бесполезным во всем вашем рабочем процессе?

Запуск программы похож на использование любого другого инструмента в вашей повседневной жизни: вам нужно принять во внимание, кто его создал, чтобы понять, как он работает, кто будет его использовать и почему, в какой среде он будет использоваться… исследование IPC (межпроцессное взаимодействие) и RPC (удаленный вызов процедур).

Отказ от ответственности: для тех, кто действительно разбирается в компьютерных науках: RPC технически также является IPC, поскольку он включает в себя два процесса, взаимодействующих друг с другом. Однако в этой статье я буду рассматривать IPC строго локально (и поэтому буду различать ситуации «на одном компьютере» и «в сети»).

Возьмем аналогию!

Предположим, у вас впереди довольно скучный день: вам нужно помыть посуду, купить продукты и постирать белье. Эти 3 задачи можно рассматривать как небольшие программы, каждая из которых «превращает» вещи во что-то другое: мытье посуды потребует грязной посуды и «производит» чистую, покупка продуктов должна превратить часть ваших денег в овощи и хлеб, а выполнение стирка такая же, как и посуда, но с одеждой.

Теперь давайте предположим еще несколько вещей:

  • у нас есть посудомоечная машина, поэтому «мытье посуды» можно перевести как: загрузить посудомоечную машину, настроить последовательность мытья, нажать «старт» и собрать результат в конце.
  • у нас есть стиральная машина, но она старая и ржавая — в основном она занимает в два раза больше времени, чем нужно, чтобы позаботиться о вашей одежде, а некоторые после этого не совсем чистые
  • с другой стороны, по соседству есть прачечная (буквально)
  • покупка продуктов требует, чтобы мы были там все время, естественно

Есть один очень простой — но нудный! — способ провести этот день: просто позаботьтесь о каждой проблеме по одной и дождитесь завершения каждого процесса, прежде чем отметить его галочкой в ​​своем списке. Это будет означать, например, что вы загружаете посудомоечную машину, а затем терпеливо сидите рядом с ней все время, пока она творит чудеса. Через несколько часов вы снова ставите блестящие тарелки в шкафы и приступаете к следующему заданию. В магазине вы проходите через полки и наполняете свою корзину, затем идете и платите за все это. Наконец, вы должны заняться стиркой. Как и в случае с посудой, вы загрузите одежду в старую стиральную машину, подождите еще дольше и в конечном итоге получите свежую, наполовину выстиранную одежду.

Вот базовое представление всех дел, которые нужно выполнить, если мы решим выполнить одну за другой:

Это называется последовательным выполнением, потому что вы запускаете серию задач. Мы можем сделать небольшую диаграмму, чтобы показать, как все пойдет:

Мы видим, что в общей сложности нам потребуется около 5 часов, чтобы позаботиться о наших задачах.

В этот момент вы могли заметить, что это довольно глупый график. В частности, такие задачи, как «посмотреть, как посудомоечная машина делает свое дело», абсолютно бесполезны. И наоборот, продуктовый магазин, хотя и не обязательно занимает большую часть нашего времени, требует, чтобы мы были там на каждом шагу, чтобы продолжать собирать продукты с полок.

В этом разница между «синхронной» и «асинхронной» задачей.

Синхронные и асинхронные задачи

Как и в нашем небольшом примере, когда вы хотите запустить две разные программы, иногда вы можете прийти к выводу, что:

  • они на самом деле не нужны друг другу для работы (здесь: мытье посуды и покупка продуктов не связаны, вы можете делать это в любом порядке, когда хотите, как хотите)
  • некоторые можно начать, а затем заниматься своими делами, пока они не закончатся, не стоя и не наблюдая: это асинхронные задачи.
  • но другим нужно, чтобы вы регулярно что-то делали, и поэтому вы не можете оставить их в покое: это синхронные задачи

Конечно, у обоих есть свои преимущества и недостатки.

Синхронные задачи могут занимать много времени, потому что они заставляют вас сосредоточиться на текущей задаче. В компьютерных науках мы говорим о «блокирующих» инструкциях: определенные строки кода, которые работают синхронно, могут занять некоторое время, чтобы завершиться полностью (например: «купить продукты»), и пока эта инструкция не будет выполнена, вы застрял и не может перейти к следующей задаче в вашем списке (следующая инструкция в вашей программе (программах)). Положительная сторона, однако, заключается в том, что когда вы (наконец) закончили с инструкцией, вы абсолютно уверены, что процесс преобразовал первоначальный ввод в желаемый вывод (ну, он может ошибаться или ошибаться, но главное в том, что : «трансформация» завершена, это не полусырой Франкенштейн в промежутке). Это означает, что если все прошло хорошо, вы полностью уверены в том, в каком состоянии находится ваша программа на данном этапе.

С другой стороны, асинхронные задачи идут по противоположному пути: вам нужно быть очень осторожным, когда оглядываетесь на свои результаты (скажем, посудомойка еще не сделана, и вы берете тарелки: они не будут полностью очищены!) но вам не нужно держать их за руку, пока они не закончатся. Существует множество примеров асинхронных задач: запросы в большой базе данных, длительные математические вычисления, независимая обработка файлов… Все это используется чаще, чем мы думаем, как часть более крупных технических продуктов, которыми мы пользуемся каждый день: поисковые системы, социальные сети, интернет-магазины и т. д. Основная идея асинхронного программирования заключается в том, что вместо того, чтобы ждать завершения задачи и следить за ней, вы ждете, пока сама задача сообщит вам, когда она будет выполнена. Таким образом, вы можете работать над собой, полностью забыть об асинхронной задаче и получать уведомление, когда асинхронная задача завершена. Это то, что делает ваша посудомоечная машина, когда она звонит в конце процесса мытья: она сообщает вам, что она закончена, поэтому вы включаете эту информацию в остальные и действуете в соответствии с ней.

Последнее важное замечание о наших задачах мыть посуду и покупать продукты: как мы упоминали ранее, между ними нет внутренней связи. Они не используют один и тот же ввод и не полагаются друг на друга. Это означает, что в идеальном мире, где мы могли бы быть везде одновременно, мы могли бы делать и то и другое одновременно без каких-либо проблем. В терминах программирования мы говорим, что их можно распараллелить (они могут жить на параллельных линиях жизни).

По сравнению с последовательным выполнением, о котором мы упоминали ранее, параллельное выполнение можно представить следующим образом:

Примечание: здесь я указываю "локальный" в заголовке, потому что позже мы увидим разницу между локальным (IPC) и удаленным (RPC) выполнением и то, как это влияет на общую продолжительность наших задач.

Мы замечаем, что, «группируя» задачи вместе, мы получаем чуть менее 3 часов свободного времени, в отличие от предыдущей «полной последовательной» схемы! Обычно это компромисс, которого мы хотим добиться в компьютерных науках, когда используем параллельное выполнение: мы уделяем немного больше времени написанию исходной программы и немного больше ресурсов выполнению, чтобы мы могли получить огромное сокращение времени выполнения взамен.

Хотя это ни в коем случае не легко сделать, для меня хороший программист всегда должен пытаться и думать о том, что может и не может быть асинхронным, чтобы извлечь максимальную пользу из текущих инструментов в предметной области. Потому что у нас есть много инструментов! На протяжении многих лет инженеры разрабатывали потрясающие аппаратные и программные средства, чтобы постепенно улучшать наши возможности по распараллеливанию задач.

Самостоятельная работа: (местный) IPC

Вы можете подумать, что наличие одного компьютера означает, что вы можете выполнять только одну задачу за раз. Но не больше! Раньше так и было, но сегодня у нас есть несколько способов обойти это, используя, например, потоки или GPU.

Как дирижер, исполняющий оперу…

На компьютере различные задачи, которые в настоящее время запланированы для обработки, называются «процессами». Итак, здесь у нас будет один процесс «мытье посуды», другой «покупка продуктов» и третий «стирка». Каждый процесс состоит из набора инструкций и контекста выполнения; в нашем случае, например, «мытье посуды» можно было бы разделить на:

  • набор инструкций: загрузите посудомоечную машину, подготовьте последовательность мытья, нажмите кнопку запуска и соберите вымытую посуду
  • контекст: какую посуду мы должны мыть на этот раз, подготовили ли мы уже последовательность мытья или нет…

Как видите, набор инструкций, вообще говоря, фиксирован (это программа, которую мы написали заранее, и она каждый раз содержит одни и те же данные), тогда как контекст более изменчив: он развивается по мере процесс выполняется, и он может содержать "динамические" данные, данные, которые зависят от момента, когда мы выполняем/просматриваем процесс. У нас может быть много тарелок, которые нужно вымыть сегодня, а на следующий день — только столовые приборы.

Внутри каждого компьютера ваша операционная система или ОС (Windows, Linux, Mac OS X…) является дирижером большого оркестра. Среди прочего, он должен иметь дело со всеми процессами, запланированными в настоящее время, чтобы гарантировать, что каждый из них получит достаточно ресурсов для правильного завершения операции. Проблема в том, что компьютер по своей природе последователен; по правде говоря, он не может работать в многозадачном режиме. Тем не менее, наши современные архитектуры способны имитировать многозадачность очень хорошо.

Ключевым моментом является очень быстрое переключение между процессами, чтобы каждый регулярно получал небольшой кусочек пирога и продолжал выполнять список инструкций, которые он должен выполнить. Если вы хотите чувствовать, что делаете успехи во всех своих делах, вы можете прыгать, чтобы выполнить небольшую инструкцию для каждой из ваших 3 задач, перейти к следующей, вернуться к первой и так далее. .

Возвращаясь к нашей базовой диаграмме задач, вот как она изменится:

В отличие от последовательного выполнения, мы не ждем, пока задача полностью завершится, прежде чем браться за следующую. Вместо этого мы просто запоминаем, где остановились в прошлый раз, и выполняем все задачи одновременно. Тем не менее, мы видим, что между каждым шагом есть некоторая задержка, требуется немного времени, чтобы перейти от одной задачи к другой. Итак, проблема в следующем: как мы можем переключаться между задачами достаточно быстро, чтобы иметь что-то похожее на многозадачность?

Примечание: в компьютере «запоминание последней остановки» осуществляется путем сохранения так называемого указателя инструкции как части контекста процесса. Всякий раз, когда ОС решает, что настала очередь для одного параллельного процесса (то есть на некоторое время), онавосстанавливаетконтекст и, в частности, благодаря этому указателю возвращается к последней выполненной инструкции.

Существуют различные способы параллельного выполнения, наиболее распространенными из которых являются потоки и графические процессоры. Это новаторские решения нашей проблемы переключения процессов, которые обеспечивают очень короткое время перехода. Потоки называются легковесными, потому что их восстановление для перехода к следующему шагу происходит очень быстро. Благодаря такой технологии мы можем сократить время переключения настолько, что создается впечатление, что мы работаем в режиме многозадачности:

Наконец-то мы получили параллельное исполнение!

Термин IPC (межпроцессное взаимодействие) относится к тому факту, что сегодня мы можем иметь некоторые взаимодействия между нашими процессами, обмен данными…

Делегирование кому-то еще: RPC

До сих пор мы фокусировались на локальном решении, т. е. на компьютерных технологиях, не предусматривающих связи между несколькими компьютерами по сети. В нашей аналогии это соответствует тому факту, что мы использовали нашу собственную посудомоечную и стиральную машины, чтобы завершить работу по дому.

Еще одна возможность удаленного выполнения с помощью удаленных вызовов процедур (RPC), чтобы иметь несколько процессов, распределенных между несколькими компьютерами, которые взаимодействуют друг с другом (с нелокальным межпроцессным взаимодействием). .

Использование лучших ресурсов

Вы помните, как у нас дома стоит очень старая малоэффективная стиральная машина? В прачечной внизу есть совершенно новые машины, которые стирают и сушат вашу одежду намного быстрее!

С этими мощными машинами задача «стирка белья» сокращает время выполнения, поэтому мы можем обновить нашу предыдущую диаграмму:

Мы видим, что теперь больше всего времени занимает посудомоечная машина, которая подтверждает, что самая медленная задача определяет общую продолжительность рабочего процесса при параллельном выполнении.

Идея делегирования части работы в сети более подготовленным участникам стала довольно модной в наши дни с появлением облачных вычислений. В настоящее время большинство крупных технологических компаний предлагают некоторые вычислительные услуги по требованию: платформа облачных вычислений Google, AWS от Amazon, IBM Cloud… Существует несколько типов услуг, но обычно они следуют принципу Платформа как услуга Модель (PaaS). Другими словами, мы сначала запрашиваем (и арендуем) виртуальную машину на серверах компании; далее мы можем войти в виртуальную машину, настроить нужную нам рабочую среду и запустить собственные программы; но нам не нужно заниматься базовой сложностью оборудования или обслуживания.

По сути: мы получаем доступ к хорошим машинам из прачечной, которые лучше, чем наши, без необходимости их обслуживания или беспокойства об их управлении.

Доплата

Конечно, в нашем капиталистическом мире поход в прачечную, чтобы постирать одежду, означает, что за это нужно будет заплатить. То же самое и для программистов: всякий раз, когда вы используете внешний сервис, вы платите. Будь то просто задержка в сети (прачечная закрыта еще на двадцать минут), перегрузка в сети (все машины на данный момент заняты и приходится ждать) или фактические сборы (монета, которую вы кладете в машину), звонки на кого-то другого, чтобы позаботиться об этом, требует оплаты.

Таким образом, хотя использование удаленного вызова процедур может помочь вам пройти лишнюю милю с точки зрения технологий, поддержки или ресурсов, это также означает, что вы заплатите за это немного больше.

Должны ли вы держать это в себе?

Еще одна проблема при использовании внешних служб — защита вашей личности и данных. Давайте будем честными: вы действительно хотите, чтобы весь район увидел ваше грязное белье? Что, если парень, который присматривает за ковриком для стирки, известен тем, что ходит и рассказывает на всю улицу все маленькие секреты? Вы бы чувствовали себя непринужденно?

То же самое и с удаленным вызовом процедур: поскольку вы соглашаетесь, чтобы другая служба выполняла грязную работу… вы соглашаетесь позволить им взглянуть на ваше грязное белье!

Я хотел бы разделить здесь две очень разные ситуации: когда вы программист и вы на самом деле тот, кто написал «удаленную процедуру», и когда вы просто пользователь, который (возможно, неосознанно) использует ее.

Первый сценарий: вы владеете прачечной

Так что да, это по-прежнему стоит вам с точки зрения энергии или арендованного пространства, но логически вы не тратите ни цента на фактическую стирку. Эта монета, которую вы кладете в автомат, возвращается в ваш карман. Кроме того, меньше риск утечки информации, потому что вы уже дома, поэтому вы выбираете, кто входит и уходит, и вы можете отказаться нанять сплетника в углу. Это означает, что вы создали целый бизнес, который, вероятно, стоил вам дорого поначалу, но теперь вы можете легко воспользоваться им.

Второй сценарий: это общественная прачечная, которую вы можете не знать изнутри и снаружи

Если вы являетесь обычным пользователем и заходите в Интернет, чтобы преобразовать какой-либо документ в PDF, вы используете удаленный вызов процедур. По сути, вы делегируете задачу конверсии онлайн-сервису. В этих случаях безопасность очень важна. Большинство сервисов конвертации файлов в файлы обещают через некоторое время удалить загруженные вами файлы, другие якобы даже не хранят ваши данные…

Помимо этих первоначальных явных правил (которые зависят от философии и определяют ее), существует также вопрос о том, как на самом деле реализуется служба, какую технологию она использует. В настоящее время существует множество инструментов и языков, из которых вы можете выбирать для создания онлайн-веб-интерфейса и скрытых за ним вычислений. Некоторые считаются более безопасными, чем другие, некоторые быстрее или эффективнее, когда много людей используют веб-сайт одновременно… в конце концов, в этом весь фокус с точки зрения программирования: когда вы пишете программу и строите вокруг нее архитектуру. , вам нужно выбрать лучшие инструменты для вашего случая (чтобы выбрать адаптированный «стек технологий», как мы говорим). Сегодня существуют базовые стандарты, которые не позволяют программистам вернуться в средневековье и обеспечивают некоторый минимальный уровень безопасности; тем не менее, если вы не настроите их должным образом на свой проект, вы не сможете сказать своим клиентам, что их данные полностью безопасны.

Как пользователям важно, чтобы мы понимали, что значит просить внешнюю службу сделать что-то для нас. Мы всегда должны читать вышеупомянутые «правила использования» и общую философию онлайн-сервиса, но важно понимать, что это не единственный уровень безопасности и что мы по-прежнему полагаемся на навыки тех, кто кодировал вещь. . Доверие к их продукту означает доверие к ним и их способности предоставить то, что они рекламируют!

Я не говорю, что мы не должны использовать эти сервисы, потому что многие из них очень удобны, и многие из них предоставляются вдумчивыми и хорошими программистами. Как обычно, речь идет скорее о том, чтобы оставаться бдительными, не принимать слепо каждое всплывающее окно, которое мы видим, или бездумно передавать наши данные кому-либо (даже службам, которым они на самом деле не нужны…).

Заключить

Это был подробный обзор сложной темы: можно многое сказать о потоках, распределенных вычислениях и сетевой связи. По правде говоря, каждый из этих терминов заслуживает нескольких статей, полностью посвященных ему!

Как бы то ни было, мне было очень весело пытаться найти красивую аналогию для описания некоторых деталей компьютера. Я добровольно решил не слишком настаивать на технических аспектах — я понимаю, что эксперты в предметной области увидят здесь большие искажения. Но мне было очень интересно приложить усилия для популяризации темы и действительно попытаться обратиться к максимально широкой аудитории.

Что насчет вас — вы думаете о задачах синхронизации и асинхронности в своих проектах? Согласны ли вы с тем, что IPC и RPC следует обсуждать с точки зрения безопасности данных? Не стесняйтесь оставлять комментарии, чтобы поделиться своими мыслями! :)

Узнать больше

  1. Учебник randu.org по потокам POSIX: https://randu.org/tutorials/threads/
  2. Определение слова GPU: https://techterms.com/definition/gpu
  3. М. Джеймс, Что такое асинхронное программирование? (https://www.i-programmer.info/programming/theory/6040-what-is-asynchronous-programming.html), июнь 2013 г. [Онлайн; последний доступ 14 июня 2020 г.].
  4. I. Фонд Викимедиа, Взаимодействие между процессами (https://en.wikipedia.org/wiki/Inter-process_communication), май 2020 г. [Онлайн; последний доступ14 июня 2020].
  5. I. Фонд Викимедиа, Удаленный вызов процедуры (https://en.wikipedia.org/wiki/Remote_procedure_call), июнь 2020 г. [Онлайн; последний доступ 14 июня 2020 г.].
  6. I. Фонд Викимедиа, Параллельные вычисления (https://en.wikipedia.org/wiki/Parallel_computing), июнь 2020 г. [Онлайн; последний доступ 14 июня 2020 г.].

Если вам понравилась эта статья, вы можете найти другие записи в блоге о технологиях, искусственном интеллекте и программировании на мой сайт :)