Этот вопрос касается низкоуровневых системных вызовов асинхронного ввода-вывода, таких как send + epoll/aio_read и других. Я спрашиваю как о сетевом вводе-выводе, так и о дисковом вводе-выводе.
Наивным способом реализации этих асинхронных вызовов было бы создание потока для каждого асинхронного запроса ввода-вывода, который затем выполнял бы запрос синхронно. Очевидно, что это наивное решение плохо масштабируется при большом количестве параллельных запросов. Даже если бы использовался пул потоков, нам все равно нужно было бы иметь один поток для каждого параллельного запроса.
Поэтому я предполагаю, что это делается следующим более эффективным способом:
Для записи/отправки данных:
Добавьте запрос на отправку в некоторую внутреннюю очередь асинхронного ввода-вывода ядра.
Выделенные «потоки записи» принимают эти запросы на отправку таким образом, что целевое оборудование полностью используется. Для этого может использоваться специальный планировщик ввода/вывода.
В зависимости от целевого оборудования запросы на запись в конечном итоге отправляются, например. через прямой доступ к памяти (DMA).
Для чтения/получения данных:
Аппаратное обеспечение инициирует прерывание ввода-вывода, которое переходит в обработчик прерывания ввода-вывода ядра.
Обработчик прерывания добавляет уведомление в очередь чтения и быстро возвращается.
Выделенные «потоки чтения» получают уведомления очереди чтения и выполняют две задачи: 1) При необходимости копируют прочитанные данные в целевой буфер. 2.) При необходимости каким-либо образом уведомить целевой процесс (например, epoll, signal,..).
Для всего этого нет необходимости иметь больше потоков записи или чтения, чем количество ядер ЦП. Следовательно, проблема масштабируемости параллельных запросов будет решена.
Как это реализовано в реальных ядрах ОС? Какие из этих предположений верны?