Главная страница
Навигация по странице:

  • Блокирующий I/O (blocking I/O).

  • Мультиплексирование I/O (multiplexing I/O).

  • Ввод вывод управляемый сигналами (signal-driven I/O).

  • Асинхронный ввод/вывод (asyncronous I/O).

  • мультиплексированный ввод. Мультиплексированный вводвывод Базовые концепции Файл фундаментальная абстракция в Linux. Linux придерживается философии все есть файл


    Скачать 148.1 Kb.
    НазваниеМультиплексированный вводвывод Базовые концепции Файл фундаментальная абстракция в Linux. Linux придерживается философии все есть файл
    Дата02.07.2022
    Размер148.1 Kb.
    Формат файлаdocx
    Имя файламультиплексированный ввод.docx
    ТипДокументы
    #622721

    Мультиплексированный ввод/вывод

    Базовые концепции
    Файл — фундаментальная абстракция в Linux. Linux придерживается философии «все есть файл», а значит большая часть взаимодействия реализуется через чтение и запись файлов. Операции с файлом осуществляются с помощью уникального дескриптора — файлового дескриптора или fd.
    Существуют обычные файлы (regular file) — это то к чему мы привыкли и специальные файлы — это некоторые объекты, которые представляются как файлы. Linux поддерживает 4 разновидности специальных файлов:

    • Файлы блочных устройств

    • Файлы устройств посимвольного ввода-вывода

    • Именованные конвейеры (named pipe или FIFO)

    • Сокеты

    Cокеты обеспечивают коммуникацию между двумя различными процессами, которые могут находится на разных компьютерах (клиент-сервер). Фактически сетевое программирование и программирование для интернета строится именно на сокетах.

    Всего в Unix подобных системах доступно 5 + 1 различных моделей ввода/вывода:

    1) Блокирующий I/O (blocking I/O). По умолчанию.

    Процесс делает системный вызов recvfrom. В результате процесс заблокируется (уйдет в сон) до тех пор, пока не придут данные и системный вызов не запишет их в буфер приложения. После этого системный вызов заканчивается (return OK) и мы можем обрабатывать наши данные.

    Недостаток — пока мы ждем данные процесс спит и не отвечает на запросы.



    2) Неблокирующий I/O (nonblocking I/O). «Если ввод/вывод, который мы хотим осуществить, невозможен без погружения процесса в блокировку (сон), то верни мне ошибку что не можешь этого сделать без блокировки.»

    Первые три раза, которые мы посылаем системный вызов на чтение не возвращают результат, т.к. ядро видит, что данных нет и просто возвращает нам ошибку EWOULDBLOCK.

    Последний системный вызов выполнится успешно, т.к. данные готовы для чтения. В результате ядро запишет данные в буфер процесса и они станут доступными для обработки.

    На этой основе можно создать цикл, который постоянно вызывает recvfrom (обращается за данными) для сокетов, открытых в неблокирующем режиме. Этот режим называется опросом (поллинг/polling) т.к. приложение все время опрашивает ядро системы на предмет наличия данных.



    3) Мультиплексирование I/O (multiplexing I/O). multiplexing - «уплотнение». «учись успевать больше». При мультиплексировании ввода/вывода мы обращаемся к одному из доступных в ОС системному вызову (мультиплексору например select, poll, pselect, dev/poll, epoll, kqueue (BSD)) и на нем блокируемся вместо того, чтобы блокироваться на фактическом I/O вызове.

    Приложение блокируется при вызове select'a ожидая, когда сокет станет доступным для чтения. Затем ядро возвращает нам статус readable и можно получать данные помощью recvfrom. В отличии от блокирующего метода, select (и любой другой мультиплексор) позволяет ожидать данные не от одного, а от нескольких файловых дескрипторов. Мультиплексор снижает время сна.

    Создается пул дескрипторов, соответствующих сокетам. Даже если при соединении нам пришел ответ EINPROGRESS это значит, что соединение устанавливается, что нам никак не мешает, т.к. мультиплексор в ходе проверки все равно возьмет тот, который первый освободился. В случае с мультиплексированием у нас в цикле проверяются ВСЕ сокеты и берется первый, который готов. Пока мы с ним работаем, другие также могут подоспеть, тоесть мы снижаем время на простой (время ожидания каждый раз сокращается).



    4) Ввод вывод управляемый сигналами (signal-driven I/O). Существует возможность использовать сигналы, заставляя ядро посылать нам сигнал вида SIGIO, когда появляется возможность считать данные без блокировки (дескриптор готов к считыванию).

    Вначале необходимо установить параметры сокета для работы с сигналами и назначить обработчик сигналов (signal handler) с помощью системного вызова sigaction. Результат возвращается мгновенно и приложение, следовательно, не блокируется. Фактически, всю работу на себя берет ядро, т.к. оно отслеживает когда данные будут готовы и посылает нам сигнал SIGIO, который вызывает установленный на него обработчик (функция обратного вызова, callback). Соответственно сам вызов recvfrom можно сделать либо в обработчике сигнала, либо в основном потоке программы. Проблема — сигнал для каждого процесса такого типа может быть только один (за раз можем работать только с одним fd).



    5) Асинхронный ввод/вывод (asyncronous I/O). Асинхронный ввод/вывод осуществляется с помощью специальных системных вызовов. Ядру дается команда начать операцию и уведомить нас (с помощью сигналов) когда операция ввода/вывода будет полностью завершена (включая копирование данных в буфер).

    Делаем системный вызов aio_read и указываем все необходимые параметры. Всю остальную работу делает за нас ядро. Должен существовать механизм, который бы уведомил процесс о том, что I/O завершен.

    Часто происходит смешение понятий между асинхронным, неблокирующим и мультиплексированным вводом выводом, тк понятие «асинхронный» трактуется по-разному. Асинхронный — значит независимый во времени (единожды запущенный он живет своей жизнью пока не выполнится, потом получаем результат)



    6) I/O в тредах/дочерних процессах. Подход, когда используется несколько потоков или процессов, в каждом из которых производится блокирующий I/O. Он похож на мультиплексирование ввода/вывода, но при этом имеет ряд недостатков (потоки в линуксе достаточно дорогие (с т.з. системных команд), что увеличивает накладные расходы). В python существует GIL и соответственно в каждый момент времени внутри 1 процесса может выполняться только один поток.

    Другой вариант — создавать дочерние процессы для обработки ввода/вывода в блокирующем стиле. Но тогда надо продумывать взаимодействие между процессами (IPC — interprocess communication).

    На практике происходит комбинирование разных моделей исходя из задачи:

    • Используют по потоку/процессу на каждую операцию с блокировкой — не выгодно

    • Много клиентов в разных тредах/процессах. Каждый тред/процесс использует мультиплексор

    • Много клиентов в разных тредах/процессах. Используется асинхронный ввод/вывод (aio)

    • Просто встраивают сервер в ядро


    написать администратору сайта