Синхронное/асинхронное программирование

Dec 06 2022
В этом блоге я пытаюсь лучше объяснить, что такое синхронное и асинхронное программирование.
Если вызывающий абонент отправляет сообщение получателю и ждет ответа, может ли он сделать что-то еще? Я говорю вызывающий/получатель вместо сервера/клиента, так как эти вызовы происходят везде. По задумке, когда мы впервые построили компьютеры, все было синхронно.
Синхронный/асинхронный

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

Синхронный ввод-вывод.
Вызывающая сторона отправляет запрос получателю, а затем блокирует его. Это когда звонящий заблокирован, ничего не делая, и, следовательно, общая трата времени. В старые времена ЦП удалял процесс из процессора, думая, что он просто заблокирован, и добавлял новый процесс, который не заблокирован (переключение контекста). Таким образом, вызывающий объект не может выполняться в это время. Наконец, когда получатель отвечает, операционная система может вернуть процесс процессору. Следовательно, вызывающий абонент разблокируется. Это показывает, как клиент и сервер полностью синхронизированы.

Пример синхронного ввода-вывода ОС:
1. Программа запрашивает ЦП прочитать файл с диска.
2. Основной поток программы снимается с процессора.
3. Чтение завершается, и программа снова начинает выполняться.

// A simple Js example
// Program starts
// Programs uses CPU to execute work.

SampleFunction();
// Program reads from the disk
// Program can't do anything until file loads
readfile("SyncExample.dat")

// Program resumes

Говоря конкретно с точки зрения NodeJs, он использует epoll в Linux, а в случае с Windows — стек завершения. Еще одна вещь, которую делает nodeJs, — запускает новый поток, который блокируется, если что-то требует выполнения блокирующей операции. По умолчанию Nodejs имеет 4 рабочих потока в библиотеке libuv , которые он использует для операций ввода-вывода, но это можно настроить.

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

// A simple Javascript example
// Program starts
// Programs uses CPU to execute work.

SampleFunction();
// Program reads from the disk
// Program hapilly moves on to the samplefunction2
readfile("SyncExample.dat", onReadFinish(console.log))
//file is not probably read yet

SampleFunction2();
//onReadFinish function called
// executing it

Теперь мы собираемся обсудить вещи исключительно с точки зрения клиента и сервера (бэкенда).
Таким образом, синхронность также может быть известна как свойство клиента, когда он может ждать или двигаться дальше. В настоящее время ни один клиент не является синхронным, и большинство библиотек асинхронны. В основном клиент отправляет запрос и получает ответ, и всякий раз, когда выполняется ответ, вызывается некоторый обратный вызов. Таким образом, в частности, в Node.js есть основной цикл цикла событий, который проверяет ответ.
Это может сбить с толку, как это всегда было для меня, когда кто-то объяснял это с помощью этого прекрасного примера из реальной жизни, что синхронность — это то же самое, что задать вопрос на собрании, где собрание продолжится, если докладчик ответит. Асинхронный — это как задать вопрос по электронной почте, на который можно ответить, когда у получателя появится время.

Асинхронная серверная обработка

Будучи бэкенд-инженером, было бы несправедливо, если бы я не говорил о том, чтобы сделать бэкэнд асинхронным. Во многих кодах/репозиториях клиент в основном асинхронный, но серверная часть все еще заставляет его ждать. Поэтому, когда клиент запрашивает отправку некоторых данных, скажем, для вызова базы данных, много раз его просят дождаться ответа от серверной части, которая возвращает ответ со статусом 200 после фиксации. Теперь, если мы переместим линзу на серверную часть, интерфейс будет асинхронным, но серверная часть останется синхронной. Так как же нам вернуть немедленный ответ?
Одно из решений — использовать эту красивую структуру данных, называемую очередью. Если клиент отправляет запрос, мы не обещаем его немедленно выполнить, а сбрасываем в очередь. Причина этого в том, что серверная часть может выполнять предыдущие запросы, а клиент больше не заблокирован; мы можем отправить ответ, что мы поставили запрос в очередь, и вот обещание/JobID. Для получения дополнительной информации вы можете прочитать об очередях сообщений .
Помимо этого, есть очень популярные решения, в зависимости от варианта использования.

Реальный пример асинхронной рабочей нагрузки:
а) Асинхронная фиксация в Postgres ↗ .
б) Асинхронный ввод-вывод в Linux (io-uring).
c) Асинхронный ввод-вывод fsync (fs-cache): Всякий раз, когда мы что-то записываем в любой файл, это не напрямую записывается на диск, а в кеш файловой системы. В операционной системе есть кеш, и записи идут на страницы. И тогда операционная система сбрасывает все страницы за один раз.

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

Спасибо за чтение; Я надеюсь, что это было полезно.
В случае дальнейших сомнений, не стесняйтесь подключаться через LinkedIn / Instagram .