Действительно ли неблокирующий ввод/вывод быстрее, чем многопоточный блокирующий ввод/вывод? Как?

Я искал в Интернете некоторые технические подробности о блокирующем и неблокирующем вводе-выводе и нашел несколько людей, утверждающих, что неблокирующий ввод-вывод будет быстрее блокирующего ввода-вывода. Например, в этом документе.

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

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

  1. Чтобы загрузить содержимое файла, приложение делегирует эту задачу основанному на событиях фреймворку ввода-вывода, передавая функцию обратного вызова вместе с именем файла
  2. Фреймворк событий делегирует операционной системе, которая программирует DMA-контроллер жесткого диска для записи файла непосредственно в память
  3. Фреймворк событий позволяет запускать дальнейший код.
  4. По завершении копирования с диска в память контроллер DMA вызывает прерывание.
  5. Обработчик прерывания операционной системы уведомляет основанный на событиях каркас ввода-вывода о том, что файл полностью загружен в память. Как он это делает? Используя сигнал?
  6. Код, который в данный момент выполняется в рамках событийного механизма ввода-вывода, завершается.
  7. Основанный на событиях фреймворк i/o проверяет свою очередь, видит сообщение операционной системы из шага 5 и выполняет обратный вызов, который он получил в шаге 1.

Так ли это работает? Если нет, то как это работает? Это означает, что система событий может работать без необходимости явного обращения к стеку (как, например, реальный планировщик, которому при переключении потоков пришлось бы создавать резервную копию стека и копировать стек другого потока в память)? Сколько времени это действительно экономит? Есть ли в этом что-то еще?

111
задан Gab是好人 30 September 2016 в 14:55
поделиться