Завершение режима ввода-вывода операционной системы

задняя часть Linux

1. Понимание ключевых понятий

  • Синхронизация: инициировать вызов и вернуть результат после получения результата.
  • Асинхронный: после того, как вызов инициирован, вызов возвращается напрямую; вызывающий активно просит вызываемого получить результат, или вызываемый передает функцию обратного вызова.
  • Блокировка: вызов означает, что текущий поток будет приостановлен до тех пор, пока не будет возвращен результат вызова. Вызывающий поток не возвращается, пока не получит результат.
  • Неблокирующий: вызов означает, что вызов не будет блокировать текущий поток, пока результат не будет немедленно доступен.

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

2. Очистить статус процесса

Понимание переходов состояний процесса

  • Состояние готовности -> состояние выполнения: после планирования процесса в состоянии готовности он получает ресурсы ЦП (назначает кванты времени ЦП), поэтому процесс переходит из состояния готовности в состояние выполнения.
  • Состояние выполнения -> состояние готовности: процесс в состоянии выполнения должен отказаться от ЦП после того, как квант времени израсходован, чтобы процесс перешел из состояния выполнения в состояние готовности. Кроме того, в вытесняющей операционной системе, когда процесс с более высоким приоритетом готов, уровень планирования переводит исполняемый процесс в состояние готовности, позволяя выполняться процессу с более высоким приоритетом.
  • Операционное состояние -> Заблокированное состояние: когда процесс запрашивает ресурс (например, периферический) или ждать использования и распределения возникновения события (например, завершение операций ввода / вывода), он переключается из рабочего состояния в состояние блокировки. Процесс запросов в виде системных вызовов операционной системы для предоставления услуг, которая является специальной формой процессов ядра операционной системы, вызываемой запуском пользовательских программ режима.
  • Состояние блокировки -> состояние готовности: когда наступает событие, которого ожидает процесс, например, завершение операции ввода-вывода или завершение прерывания, обработчик прерывания должен преобразовать состояние соответствующего процесса из заблокированного состояния. до состояния готовности.

3. Запустите приложение на уровне операционной системы, чтобы понять модель ввода-вывода.

Блокирующая модель ввода-вывода:

  • Введение. Процесс будет заблокирован до тех пор, пока копирование данных не будет завершено и приложение не вызовет функцию ввода-вывода, в результате чего приложение заблокируется и будет ждать готовности данных. Если данные не готовы, продолжайте ждать... Данные готовы, скопированы из ядра в пространство пользователя, и функция ввода-вывода возвращает индикацию успеха. Первое сетевое программирование, с которым мы познакомились, началось с таких интерфейсов, как listen(), send() и recv(). С помощью этих интерфейсов можно легко построить модели сервер/клиент.
  • Диаграмма модели блокирующего ввода-вывода: процесс ожидания данных и копирования данных в ядре происходит при вызове функции recv()/recvfrom().

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

Неблокирующая модель ввода-вывода

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

Модель повторного использования ввода-вывода:

  • Введение: Мультиплексирование ввода-вывода — это то, что мы называем select, poll и epoll.В некоторых местах этот метод ввода-вывода также называется вводом-выводом, управляемым событиями. Преимущество select/epoll заключается в том, что один процесс может обрабатывать ввод-вывод нескольких сетевых подключений одновременно. Его основной принцип заключается в том, что функции select, poll и epoll будут непрерывно опрашивать все сокеты, за которые они отвечают, и когда в определенный сокет поступают данные, он уведомляет пользовательский процесс.

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

Модель асинхронного ввода-вывода

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

4. Различать выбор опроса epoll в мультиплексировании ввода-вывода

select

int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); selectФайловые дескрипторы, отслеживаемые функцией, делятся на три категории, а именно:writefds,readfds,а такжеexceptfds. После вызова функция select будет блокироваться до тех пор, пока дескриптор не будет готов (данные доступны для чтения, записи или исключения) или пока не истечет время ожидания (время ожидания указывает время ожидания, если оно возвращается немедленно, для него может быть установлено значение null), и функция возвращается. Когда функция выбора возвращается, вы можете Найдите готовый дескриптор, перейдя по fdset

poll

int poll (struct pollfd *fds, unsigned int nfds, int timeout);В отличие от того, как select использует три растровых изображения для представления трех fdset, опрос использует одинpollfdреализация указателя. У pollfd нет ограничения на максимальное число (но производительность также снизится, если число будет слишком большим). Как и функция select, после завершения опроса pollfd необходимо опрашивать, чтобы получить готовый дескриптор.

epoll

epoll — это готовый метод оповещения через событие, вызывающийepoll_createСоздайте экземпляр, позвонитеepoll_ctlЧтобы добавить или удалить отслеживаемые файловые дескрипторы, вызовитеepoll_waitБлокировать до тех пор, пока не появится готовый файловый дескриптор, черезepoll_eventПараметры возвращают дескриптор файла и событие для состояния готовности.

Процесс работы epoll требует наличия трех интерфейсов, а именно:int epoll_create(int size);//创建一个epoll的句柄, размер используется, чтобы сообщить ядру, насколько велико количество мониторов.Чтобы сгенерировать файловый дескриптор, предназначенный для epoll, нужно применить пространство ядра для хранения того, произошли ли и какие события произошли на сокете fd, на которые вы хотите обратить внимание. .

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
Управление событиями файлового дескриптора epoll: регистрация, изменение, удаление. Где параметр epfd — это дескриптор файла, предназначенный для epoll_create() для создания epoll.

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
Ожидает возникновения события ввода-вывода; возвращает количество произошедших событий. Описание параметра:
epfd: Epoll_create () сгенерированный файловый дескриптор, специфичный epoll;
epoll_event: Массив, используемый для передачи обратно и обрабатывать события;
maxevents: Количество событий, которые можно обрабатывать каждый раз;
timeout: Значение тайм-аута для ожидания возникновения события ввода/вывода;

сводка различий

(1) Реализация select, poll должна непрерывно опрашивать все наборы fd самостоятельно, пока устройство не будет готово, в течение которого оно может чередоваться между спящим режимом и пробуждением несколько раз. На самом деле, epoll также должен вызывать epoll_wait для непрерывного опроса списка готовности, в течение периода сон и пробуждение могут много раз чередоваться, но когда устройство готово, оно вызывает callback-функцию, кладет готовый фд в готовый list и просыпается, чтобы заснуть в процессе epoll_wait. Несмотря на то, что как sleep, так и alter, select и poll должны пройти через всю коллекцию fd, когда «бодрствуют», а epoll нужно только оценить, пуст ли список готовых файлов, когда «бодрствует», что экономит много процессорного времени. Это улучшение производительности, вызванное механизмом обратного вызова. (2) Выберите и скопируйте набор fd из пользовательского режима в режим ядра каждый раз, когда он вызывается, epoll Пространство ядра и пространство пользователя отображаются на один и тот же участок памяти через mmap, что устраняет необходимость в операциях копирования.

Примеры применения

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

Модуль Tornado IOLoop является ядром асинхронного механизма, который содержит список дескрипторов открытых файлов и обработчиков для каждого дескриптора. Эти обработчики являются инкапсуляцией select, poll, epoll и т. д. (Так что по сути это мультиплексирование ввода-вывода)

  • Django
    Вместо использования асинхронности параллелизм достигается за счет использования многопроцессорного сервера WSGI (такого как uWSGI), что также является обычной практикой в ​​WSGI.