Асинхронный ввод-вывод
Эта статья нуждается в дополнительных цитатах для проверки . ( июнь 2014 г. ) |
Эту статью может потребовать очистки Википедии , чтобы она соответствовала стандартам качества . Конкретная проблема заключается в том, что асинхронный и неблокирующий подходы — это разные подходы. ( сентябрь 2017 г. ) |
В информатике асинхронный ввод-вывод (также непоследовательный ввод-вывод ) — это форма обработки ввода-вывода , которая позволяет продолжить другую обработку до завершения операции ввода-вывода. Имя, используемое для асинхронного ввода-вывода в Windows API, называется перекрывающимся вводом-выводом .
Операции ввода и вывода (I/O) на компьютере могут быть чрезвычайно медленными по сравнению с обработкой данных. Устройство ввода-вывода может включать в себя механические устройства, которые должны физически перемещаться, например жесткий диск, ищущий дорожку для чтения или записи; часто это происходит на порядки медленнее, чем переключение электрического тока. Например, во время дисковой операции, выполнение которой занимает десять миллисекунд, процессор с тактовой частотой один гигагерц мог бы выполнить десять миллионов циклов обработки инструкций.
Простой подход к вводу-выводу — начать доступ, а затем дождаться его завершения. Но такой подход, называемый синхронным вводом-выводом или блокирующим вводом-выводом , блокирует выполнение программы во время обмена данными, оставляя системные ресурсы незадействованными. Когда программа выполняет множество операций ввода-вывода (например, программа в основном или в значительной степени зависит от пользовательского ввода ), это означает, что процессор может проводить почти все свое время в режиме ожидания, ожидая завершения операций ввода-вывода.
В качестве альтернативы можно начать связь, а затем выполнить обработку, которая не требует завершения ввода-вывода. Этот подход называется асинхронным вводом/выводом. Любая задача, которая зависит от завершения операции ввода-вывода (это включает в себя как использование входных значений, так и критические операции, которые утверждают, что операция записи завершена), все равно должна ждать завершения операции ввода-вывода и, следовательно, все еще заблокирован, но другая обработка, не зависящая от операции ввода-вывода, может продолжаться.
Существует множество функций операционной системы для реализации асинхронного ввода-вывода на многих уровнях. Фактически, одной из основных функций всех операционных систем, кроме самых элементарных , является выполнение хотя бы той или иной формы базового асинхронного ввода-вывода, хотя это может быть не особенно очевидно для пользователя или программиста. В простейшем программном решении состояние аппаратного устройства опрашивается через определенные промежутки времени, чтобы определить, готово ли устройство к следующей операции. (Например, операционная система CP/M была построена таким образом. Ее семантика системных вызовов не требовала более сложной структуры ввода-вывода, чем эта, хотя большинство реализаций были более сложными и, следовательно, более эффективными.) Прямой доступ к памяти (DMA ) ) может значительно повысить эффективность системы, основанной на опросе, а аппаратные прерывания могут полностью исключить необходимость опроса. Многозадачные операционные системы могут использовать функциональные возможности аппаратных прерываний, скрывая при этом от пользователя сложность обработки прерываний. Намотка была одной из первых форм многозадачности, предназначенной для использования асинхронного ввода-вывода. Наконец, многопоточность асинхронного ввода-вывода и явные API-интерфейсы в пользовательских процессах могут дополнительно использовать асинхронный ввод-вывод за счет дополнительной сложности программного обеспечения.
Асинхронный ввод-вывод используется для повышения энергоэффективности, а в некоторых случаях и пропускной способности. Однако в некоторых случаях это может иметь негативное влияние на задержку и пропускную способность.
Формы
[ редактировать ]Формы ввода-вывода и примеры функций POSIX:
Блокировка | Неблокирующий | Асинхронный | |
---|---|---|---|
API | писать, читать | пишите, читайте + опрос/выбор | aio_write, aio_read |
Все формы асинхронного ввода-вывода подвергают приложения риску потенциальных конфликтов ресурсов и связанных с ними сбоев. тщательное программирование (часто с использованием взаимного исключения , семафоров Чтобы предотвратить это, требуется и т. д.).
При предоставлении асинхронного ввода-вывода приложениям существует несколько широких классов реализации. Форма API , предоставляемая приложению, не обязательно соответствует механизму, фактически предоставляемому операционной системой; возможны эмуляции. Более того, в одном приложении может использоваться более одного метода, в зависимости от его потребностей и желаний его программиста(ов). Многие операционные системы предоставляют более одного из этих механизмов, возможно, что некоторые могут предоставлять их все.
Процесс
[ редактировать ]Доступно в ранних версиях Unix. В многозадачной операционной системе обработка может быть распределена между различными процессами, которые выполняются независимо, имеют собственную память и обрабатывают собственные потоки ввода-вывода; эти потоки обычно соединяются трубопроводами . Процессы довольно дороги в создании и поддержании. [ нужна ссылка ] поэтому это решение работает хорошо только в том случае, если набор процессов небольшой и относительно стабильный. Также предполагается, что отдельные процессы могут работать независимо, помимо обработки ввода-вывода друг друга; если им нужно общаться другими способами, их координация может стать затруднительной. [ нужна ссылка ]
Расширением этого подхода является программирование потоков данных , которое позволяет создавать более сложные сети, чем просто цепочки, поддерживаемые конвейерами.
Опрос
[ редактировать ]Вариации:
- Ошибка, если это еще невозможно сделать (повторить позже)
- Сообщите, когда это можно будет сделать без блокировки (затем выдайте это)
Опрос предоставляет неблокирующий синхронный API, который можно использовать для реализации некоторых асинхронных API. Доступно в традиционных Unix и Windows . Его основная проблема заключается в том, что он может многократно тратить время процессора на опрос, когда процессу выдачи больше нечего делать, что сокращает время, доступное для других процессов. Кроме того, поскольку приложение опроса по существу является однопоточным, оно может оказаться неспособным в полной мере использовать параллелизм ввода-вывода, на который способно аппаратное обеспечение.
Циклы выбора (/опроса)
[ редактировать ]Доступен в BSD Unix и почти во всем остальном со стеком протоколов TCP/IP , который либо использует реализацию BSD, либо моделирует ее. Вариация на тему опроса: цикл выбора использует метод select
системный вызов переходит в режим сна не возникнет условие до тех пор, пока в дескрипторе файла (например, когда данные доступны для чтения), не истечет время ожидания или не будет получен сигнал (например, когда дочерний процесс завершается). Изучив возвращаемые параметры select
вызов, цикл определяет, какой дескриптор файла изменился, и выполняет соответствующий код. Часто для простоты использования цикл выбора реализуется как цикл событий , возможно, с использованием функций обратного вызова ; эта ситуация особенно хорошо подходит для событийно-ориентированного программирования .
Хотя этот метод надежен и относительно эффективен, он во многом зависит от парадигмы Unix , согласно которой « все является файлом »; любой блокирующий ввод-вывод, не задействующий файловый дескриптор, заблокирует процесс. Цикл выбора также полагается на возможность задействовать все операции ввода-вывода в центральном процессоре. select
вызов; В этом отношении особенно проблематичны библиотеки, которые осуществляют собственный ввод-вывод. Дополнительная потенциальная проблема заключается в том, что операции выбора и ввода-вывода все еще достаточно разделены, поэтому результат выбора может фактически быть ложью: если два процесса читают из одного файлового дескриптора (возможно, плохой дизайн), выбор может указывать на доступность чтения. данные, которые исчезли к моменту выполнения чтения, что привело к блокировке; если два процесса записывают в один файловый дескриптор (не так уж и редко), выбор может указывать на немедленную возможность записи, но запись все равно может блокироваться, потому что буфер был заполнен другим процессом в промежуточный период или из-за того, что запись слишком велика для доступного буфера или другими способами, неподходящими для получателя.
Цикл выбора не достигает максимальной эффективности системы, возможной, скажем, с помощью метода очередей завершения , поскольку семантика select
вызов, позволяющий настраивать приемлемый набор событий для каждого вызова, требует некоторого количества времени на каждый вызов, проходящий через массив выбора. Это создает небольшие накладные расходы для пользовательских приложений, которые могут открывать один файловый дескриптор для оконной системы и несколько для открытых файлов, но становится все более серьезной проблемой по мере роста числа потенциальных источников событий и может препятствовать разработке многоклиентских серверных приложений. , как в задаче C10k ; в таких случаях другие асинхронные методы могут быть заметно более эффективными. Некоторые Unix-системы предоставляют специфичные для системы вызовы с лучшим масштабированием; например, epoll
в Linux (который заполняет возвращаемый массив выбора только теми источниками событий, в которых событие произошло), kqueue
во FreeBSD и порты событий (и /dev/poll
) в Солярисе .
SVR3 Unix предоставил poll
системный вызов. Возможно, имя лучше, чем select
, для целей данного обсуждения это, по сути, одно и то же. Unix-системы SVR4 (и, следовательно, POSIX ) предлагают оба вызова.
Сигналы (прерывания)
[ редактировать ]Доступен в BSD и POSIX Unix. Ввод-вывод выполняется асинхронно, и по его завершению сигнал ( прерывание генерируется ). Как и в низкоуровневом программировании ядра, возможности, доступные для безопасного использования в обработчике сигналов, ограничены, и основной поток процесса может быть прерван практически в любой момент, что приводит к несогласованным структурам данных, видимым обработчиком сигналов. Обработчик сигнала обычно не может самостоятельно выполнять дальнейшие асинхронные операции ввода-вывода.
Сигнальный подход, хотя и относительно прост в реализации в ОС, привносит в прикладную программу нежелательный багаж , связанный с написанием системы прерываний ядра операционной системы. Его худшей характеристикой является то, что каждый блокирующий (синхронный) системный вызов потенциально может быть прерван; программист обычно должен включать код повтора при каждом вызове. [ нужна ссылка ]
Функции обратного вызова
[ редактировать ]Этот раздел нуждается в дополнительных цитатах для проверки . ( июль 2022 г. ) |
Доступно в классической Mac OS , VMS и Windows . Имеет многие характеристики сигнального метода , поскольку по сути это то же самое, хотя и редко признается таковым. Разница в том, что каждый запрос ввода-вывода обычно может иметь свою собственную функцию завершения, тогда как сигнальная система имеет единственный обратный вызов.
С другой стороны, потенциальная проблема использования обратных вызовов заключается в том, что глубина стека может неконтролируемо расти, поскольку чрезвычайно распространенной вещью, которую нужно сделать после завершения одного ввода-вывода, является планирование другого. Если это должно быть выполнено немедленно, первый обратный вызов не будет «размотан» из стека до вызова следующего. Системы предотвращения этого (например, «промежуточное» планирование новой работы) усложняют работу и снижают производительность. На практике, однако, это обычно не является проблемой, поскольку новый ввод-вывод обычно сам возвращается, как только новый ввод-вывод запускается, позволяя «размотать» стек. Проблему также можно предотвратить, избегая любых дальнейших обратных вызовов с помощью очереди до тех пор, пока не вернется первый обратный вызов.
Легкие процессы или потоки
[ редактировать ]Облегченные процессы (LWP) или потоки доступны в большинстве современных операционных систем. Аналогично процессному методу, но с меньшими накладными расходами и без изоляции данных, затрудняющей координацию потоков. Каждый LWP или поток сам по себе использует традиционный блокирующий синхронный ввод-вывод, что упрощает логику программирования; это обычная парадигма, используемая во многих языках программирования, включая Java и Rust. Для многопоточности необходимо использовать механизмы синхронизации, предоставляемые ядром, и потокобезопасные библиотеки. Этот метод не наиболее подходит для чрезвычайно крупномасштабных приложений, таких как веб-серверы, из-за большого количества необходимых потоков.
Этот подход также используется в системе времени выполнения языка программирования Erlang . Erlang Виртуальная машина использует асинхронный ввод-вывод, используя небольшой пул, состоящий всего из нескольких потоков или иногда только одного процесса, для обработки ввода-вывода от миллионов процессов Erlang. Обработка ввода-вывода в каждом процессе в основном записывается с использованием блокирующего синхронного ввода-вывода. Таким образом, высокая производительность асинхронного ввода-вывода сочетается с простотой обычного ввода-вывода (см. модель актера ). Многие проблемы ввода-вывода в Erlang связаны с передачей сообщений, которую можно легко решить с помощью встроенного выборочного приема.
Волокна / сопрограммы можно рассматривать как такой же легкий подход для выполнения асинхронного ввода-вывода вне системы времени выполнения Erlang, хотя они не предоставляют точно таких же гарантий, как процессы Erlang.
Очереди/порты завершения
[ редактировать ]Доступно в Microsoft Windows , Solaris , AmigaOS , DNIX и Linux (с использованием io_uring , доступно в версии 5.1 и выше). [1] Запросы ввода-вывода выдаются асинхронно, но уведомления о завершении предоставляются через механизм синхронизирующей очереди в порядке их выполнения. Обычно связано со конечном автомате структурированием основного процесса на ( программирование, управляемое событиями ), которое может мало напоминать процесс, который не использует асинхронный ввод-вывод или использует одну из других форм, затрудняя повторное использование кода. [ нужна ссылка ] . Не требует дополнительных специальных механизмов синхронизации или потокобезопасных библиотек, а также не разделены текстовые (код) и временные (события) потоки.
Флаги событий
[ редактировать ]Доступен в VMS и AmigaOS (часто используется вместе с портом завершения). Имеет многие характеристики метода очереди завершения , поскольку по сути является очередью завершения первой глубины. Чтобы имитировать эффект «глубины» очереди, для каждого потенциального необработанного (но завершенного) события требуется дополнительный флаг события, иначе информация о событии может быть потеряна. Ожидание следующего доступного события в таком скоплении требует механизмов синхронизации, которые могут плохо масштабироваться для большего количества потенциально параллельных событий.
Канальный ввод/вывод
[ редактировать ]Доступно в мэйнфреймах IBM , Groupe Bull и Unisys . Канал ввода-вывода предназначен для максимального использования и пропускной способности ЦП за счет переноса большей части операций ввода-вывода на сопроцессор. Сопроцессор имеет встроенный DMA, обрабатывает прерывания устройств, управляется основным процессором и прерывает работу основного процессора только тогда, когда это действительно необходимо. Эта архитектура также поддерживает так называемые канальные программы, которые выполняются на канальном процессоре и выполняют тяжелую работу по операциям ввода-вывода и протоколам.
Зарегистрированный ввод-вывод
[ редактировать ]Доступно в Windows Server 2012 и Windows 8 . Оптимизирован для приложений, обрабатывающих большое количество небольших сообщений, для достижения большего количества операций ввода-вывода в секунду с уменьшенным джиттером и задержкой. [2]
Этот раздел нуждается в расширении . Вы можете помочь, добавив к нему . ( май 2014 г. ) |
Выполнение
[ редактировать ]Этот раздел написан как личное размышление, личное эссе или аргументативное эссе , в котором излагаются личные чувства редактора Википедии или представлены оригинальные аргументы по определенной теме. ( февраль 2016 г. ) |
Подавляющее большинство вычислительного оборудования общего назначения полностью полагается на два метода реализации асинхронного ввода-вывода: опрос и прерывания. Обычно оба метода используются вместе, баланс во многом зависит от конструкции оборудования и его требуемых характеристик производительности. ( DMA сам по себе не является еще одним независимым методом, это просто средство, с помощью которого можно выполнить больше работы за опрос или прерывание.)
Чистые системы опроса вполне возможны, небольшие микроконтроллеры (например, системы, использующие PIC ) часто строятся таким образом. Системы CP/M также могли быть построены таким образом (хотя это было редко), с DMA или без него. Кроме того, когда максимальная производительность необходима только для нескольких задач в ущерб любым другим потенциальным задачам, опрос также может быть уместным, поскольку накладные расходы на обработку прерываний могут быть нежелательны. (Обслуживание прерывания требует времени [и пространства] для сохранения хотя бы части состояния процессора, а также времени, необходимого для возобновления прерванной задачи.)
Большинство вычислительных систем общего назначения в значительной степени полагаются на прерывания. Возможна чистая система прерываний, хотя обычно также требуется некоторый компонент опроса, поскольку очень часто несколько потенциальных источников прерываний используют общую линию сигнала прерывания, и в этом случае опрос используется в драйвере устройства для разрешения проблемы. фактический источник. (Это время разрешения также способствует снижению производительности системы прерываний. За прошедшие годы была проделана большая работа, чтобы попытаться минимизировать накладные расходы, связанные с обслуживанием прерывания. Современные системы прерываний довольно вялые по сравнению с некоторыми тщательно настроенными более ранними системами. , но общее увеличение производительности оборудования значительно смягчило эту ситуацию.)
Возможны также гибридные подходы, в которых прерывание может инициировать начало некоторого пакета асинхронного ввода-вывода, а опрос используется внутри самого пакета. Этот метод распространен в драйверах высокоскоростных устройств, таких как сетевые или дисковые, где время, потерянное при возврате к задаче перед прерыванием, превышает время до следующего требуемого обслуживания. (Обычное оборудование ввода-вывода, используемое в наши дни, в значительной степени зависит от DMA и больших буферов данных, чтобы компенсировать относительно низкую производительность системы прерываний. Они обычно используют опрос внутри циклов драйвера и могут демонстрировать огромную пропускную способность. В идеале для каждого значения опросы всегда успешны или, самое большее, повторяются небольшое количество раз.)
Когда-то такой гибридный подход был распространен в дисковых и сетевых драйверах, где не было DMA или значительной буферизации. Поскольку желаемая скорость передачи была выше, чем могла выдержать минимальный цикл с четырьмя операциями на каждый элемент данных (проверка битов, условный переход к самому себе, выборка и сохранение), аппаратное обеспечение часто создавалось с автоматической состояния ожидания генерацией . на устройстве ввода-вывода, передавая опрос о готовности данных из программного обеспечения на аппаратное обеспечение процессора для выборки или хранения и сокращая программный цикл до двух операций. (Фактически, используя сам процессор в качестве механизма DMA.) Процессор 6502 предлагал необычные средства для обеспечения трехэлементного цикла для каждого элемента данных, поскольку у него был аппаратный вывод, который, когда он установлен, вызывал срабатывание бита переполнения процессора. установить напрямую. (Очевидно, что при проектировании оборудования следует проявлять большую осторожность, чтобы избежать переопределения бита переполнения вне драйвера устройства!)
Синтез
[ редактировать ]Используя только эти два инструмента (опрос и прерывания), все остальные формы асинхронного ввода-вывода, обсуждавшиеся выше, могут быть синтезированы (и фактически так и есть).
В такой среде, как виртуальная машина Java (JVM), асинхронный ввод-вывод может быть синтезирован, даже если среда, в которой работает JVM, может вообще не предлагать его. Это связано с интерпретируемой природой JVM. JVM может периодически опрашивать (или прерывать) для запуска внутреннего потока изменения управления, что приводит к появлению нескольких одновременных процессов, по крайней мере некоторые из которых предположительно существуют для выполнения асинхронного ввода-вывода. (Конечно, на микроскопическом уровне параллелизм может быть довольно грубым и иметь некоторые неидеальные характеристики, но на первый взгляд он будет выглядеть так, как хотелось бы.)
Фактически, в этом и заключается проблема использования опроса в любой форме для синтеза другой формы асинхронного ввода-вывода. Каждый цикл процессора, являющийся опросом, тратится впустую и теряется из-за накладных расходов, а не для выполнения желаемой задачи. Каждый цикл ЦП, не являющийся опросом, представляет собой увеличение задержки реакции на ожидающий ввод-вывод. Достичь приемлемого баланса между этими двумя противоборствующими силами сложно. (Именно поэтому были изобретены аппаратные системы прерываний.)
Чтобы максимизировать эффективность, необходимо минимизировать объем работы, которую необходимо выполнить при получении прерывания, чтобы разбудить соответствующее приложение. Во-вторых (но, возможно, не менее важно) — это метод, который само приложение использует для определения того, что ему нужно делать.
Особенно проблематичными (с точки зрения эффективности приложений) являются открытые методы опроса, включая механизмы выбора/опроса. Хотя базовые события ввода-вывода, в которых они заинтересованы, по всей вероятности, управляются прерываниями, взаимодействие с этим механизмом опрашивается и может занять большое количество времени при опросе. Это особенно верно в отношении потенциально крупномасштабного опроса, возможного с помощью select (и poll). Прерывания очень хорошо сопоставляются с сигналами, функциями обратного вызова, очередями завершения и флагами событий. Такие системы могут быть очень эффективными.
Примеры
[ редактировать ]Следующие примеры демонстрируют три подхода к чтению ввода-вывода. Объекты и функции абстрактны.
1. Блокировка, синхронность:
device = IO.open()data = device.read() # thread will be blocked until there is data in the deviceprint(data)
2. Блокирующий и неблокирующий, синхронный: (здесь IO.poll()
блокируется на срок до 5 секунд, но device.read()
нет)
device = IO.open()ready = Falsewhile not ready: print("There is no data to read!") ready = IO.poll(device, IO.INPUT, 5) # returns control if 5 seconds have elapsed or there is data to read (INPUT)data = device.read()print(data)
3. Неблокирующий, асинхронный:
ios = IO.IOService()device = IO.open(ios)def inputHandler(data, err): "Input data handler" if not err: print(data)device.readSome(inputHandler)ios.loop() # wait till all operations have been completed and call all appropriate handlers
Вот тот же пример с Async/await :
ios = IO.IOService()device = IO.open(ios)async def task(): try: data = await device.readSome() print(data) except Exception: passios.addTask(task)ios.loop() # wait till all operations have been completed and call all appropriate handlers
Вот пример с шаблоном Reactor :
device = IO.open()reactor = IO.Reactor()def inputHandler(data): "Input data handler" print(data) reactor.stop()reactor.addHandler(inputHandler, device, IO.INPUT)reactor.run() # run reactor, which handles events and calls appropriate handlers
См. также
[ редактировать ]Ссылки
[ редактировать ]- ^ Корбет, Джонатан. «Вызов нового API асинхронного ввода-вывода» . LWN.net . Проверено 27 июля 2020 г.
- ^ «Зарегистрированные расширения API ввода-вывода (RIO)» . technet.microsoft.com . 31 августа 2016 г.
Внешние ссылки
[ редактировать ]- Проблема C10K ; обзор методов асинхронного ввода-вывода с упором на масштабирование – Дэн Кегель
- Статья « Повышение производительности приложений с помощью асинхронного ввода-вывода » М. Тима Джонса
- Статья « Отложенный асинхронный ввод-вывод для серверов, управляемых событиями » Вилли Звенепола , Халеда Элмелиги , Анупама Чанды и Алана Л. Кокса
- Выполнение операций ввода-вывода параллельно
- Описание из стандарта POSIX
- Внутри портов завершения ввода-вывода Марк Руссинович
- Описание из Руководства разработчика .NET Framework.
- Асинхронный ввод-вывод и обозреватель асинхронного дискового ввода-вывода
- IO::AIO — это модуль Perl, предлагающий асинхронный интерфейс для большинства операций ввода-вывода.
- ACE Проактор