tgoop.com/careerunderhood/321
Last Update:
CPU, Memory Models, Concurrency, Multiprocess, Multithreading и Async. Часть 9. Asynchronous IO
Пора провести промежуточный итог для цикла статей. И закончим мы его как и планировалось - поиском ответом на вопрос: что же значит термин Async IO с точки зрения OC?
Но чтобы дать ответ на этот вопрос мне потребуется сделать несколько шагов назад и рассказать о том как исполняются программы с точки зрения ОС.
Программа может находиться в 2х режимах - Режим пользователя (User Mode) и Режим Ядра (Kernel Mode).
Если говорить очень простым языком - первый это когда программа выполняет код написанный разработчиком (циклы, функции, вычисления итп). Второй же нужен когда нам нужно обратиться к системным ресурсам (работа с файлом, сетевым интерфейсом). В режим ядра программа попадает при работе с системными вызовами (всеми теми разобранными в постах ранее).
Взаимодействие с ядром в большинстве случаев происходит в синхронном режиме и является блокирующим. То есть поток исполнения инструкций нашей программы остановится ожидая от ОС результатов вызова функции.
И вот это узкое горлышко очень хотелось оптимизировать разработчикам ОС, и для этого было предпринято ряд приседаний:
- для системных вызовов в Linux добавилась поддержка работы в неблокирующем режиме. В таком случае на плечи программиста будет ложиться ответственность за написание кода который будет повторять например операцию чтения пока в сокете не появятся байты так как ОС никак не уведомит программу что данные пора читать. Но вызов сам по себе максимально быстрый, особенно если перед этим мы убедились с помощью select / epoll что в сокете данные уже есть.
- aio(7) - поддержка настоящего асинхронного ввода-вывода. Если простым языком то системные вызовы также не блокирующие но изменяется механизм уведомления - ОС пошлет нам сигнал что пора бы начать читать данные из сокета. (Возможно здесь вы словили мысль "что-то мне это напоминает")
- io_uring - развитие идей aio (по итогу aio слили с io_uring). Умеет работать не только с сетью но и с файлами и блочными устройствами асинхронно. Один из самых современных подходов к разработке асинхронных программ. Биндинги к этому интерфейсу постепенно появляются в языках программирования.
Ок, тут мы разобрались, в линуксе есть системные вызовы, позволяющие делать настоящие асинхронные программы для задач связанных с IO. Но ведь большинство языков и программ используют врапперы над обычными epoll / select, во многих ЯП давно можно делать async / await или например создать promise и всё будет работать? Что это за магия?
Ответ: Из за отсутствия удобного API для асинхронного программирования на уровне OC стали появляться инструменты предоставляющие асинхронные абстракции в user mode (рантайм языка программирования) - Eventloop, reactor, fiber, coroutines, channels, futures, promises.
Благодаря этому разработчик может писать асинхронный код с точки зрения ЯП, оперировать понятиями асинхронного программирования, хотя под капотом с точки зрения ОС ничего асинхронного в программе может и не быть.
На этом всё, спасибо что читали, надеюсь было интересно и познавательно😇
Доп ссылки:
- What is io_uring?
- Does all system calls execute in kernel mode?
- Understanding asynchronous I/O; building an event loop from scratch
- Difference Between User Mode and Kernel Mode
- Linux fundamentals: user space, kernel space, and the syscalls API surface
BY Евгений Козлов пишет про IT
Share with your friend now:
tgoop.com/careerunderhood/321