Каков статус асинхронного ввода-вывода POSIX (AIO)?

Существуют страницы, разбросанные по сети, которые описывают объекты POSIX AIO в различном количестве деталей. Ни один из них не ужасно недавний. Неясно, что именно они описывают. Например, официальный сайт (?) для поддержки асинхронного ввода-вывода ядра Linux здесь говорит, что сокеты не работают, но На страницах руководства "aio.h" на моей рабочей станции Ubuntu 8.04.1 все, кажется, подразумевает, что он работает для произвольных дескрипторов файлов. Затем другой проект, который, кажется, работает на уровне библиотеки с еще меньшей документацией.

Я хотел бы знать:

  • Какова цель POSIX AIO? Учитывая, что наиболее очевидный пример реализации, который я могу найти, говорит, что он не поддерживает сокеты, все это кажется мне странным. Это просто для ввода/вывода асинхронного диска? Если да, то почему гипер-общий API? Если нет, то почему диск ввода/вывода - первое, на что на него напали?
  • Где есть примеры завершенных программ POSIX AIO, на которые я могу смотреть?
  • Кто-нибудь действительно использует его, на самом деле?
  • Какие платформы поддерживают POSIX AIO? Какие части этого они поддерживают? Кто-нибудь действительно поддерживает подразумеваемый "Любой ввод-вывод для любого FD", который, по-видимому, обещает <aio.h>?

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

Ответ 1

Сетевой ввод-вывод не является приоритетом для AIO, потому что все, кто пишет сетевые серверы POSIX, используют неблокирующий подход на основе событий. В старом стиле Java "миллиарды блокирующих потоков" подходят ужасно.

Диск-запись ввода-вывода уже буферизована, и чтение/ввод данных с диска можно предварительно запрограммировать в буфер, используя такие функции, как posix_fadvise. Это оставляет прямой, небуферизованный дисковый ввод-вывод как единственную полезную цель для AIO.

Прямой, небуферизованный ввод-вывод действительно полезен только для транзакционных баз данных, и они склонны писать свои собственные потоки или процессы для управления своими дисковыми вводами/выводами.

Итак, в конце, что оставляет POSIX AIO в позиции не обслуживающей любой полезной цели. Не используйте его.

Ответ 2

Эффективное выполнение ввода-вывода сокетов было разрешено с помощью портов kqueue, epoll, ввода-вывода IO и подобных. Выполнение асинхронного ввода-вывода файлов - это своего рода поздний посетитель (кроме перекрытия окон и ввода-вывода Solaris для ранней поддержки posix AIO).

Если вы ищете выполнение ввода/вывода сокетов, вам, вероятно, лучше использовать один из вышеперечисленных механизмов.

Таким образом, основная задача AIO - решить проблему асинхронного ввода-вывода. Скорее всего, Mac OS X поддерживает только AIO для обычных файлов, а не сокетов (поскольку kqueue делает это намного лучше).

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

Однако для операций чтения, если вы хотите, чтобы ядро ​​приоритизировало и заказывало ваши чтения, AIO действительно единственный вариант. Вот почему ядро ​​может (теоретически) делать это лучше, чем любое приложение уровня пользователя:

  • Ядро видит все дисковые операции ввода-вывода, а не только задания на диске приложений, и может заказывать их на глобальном уровне.
  • Ядро (может) знать, где находится голова чтения диска, и может выбрать задание чтения, которое вы передаете ему в оптимальном порядке, чтобы переместить голову на самое короткое расстояние.
  • Ядро может использовать собственную очередь очереди, чтобы оптимизировать ваши операции чтения
  • Возможно, вам удастся выполнить больше операций чтения за системный вызов с помощью lio_listio(), чем с помощью readv(), особенно если ваши чтения не являются (логически) смежными, сохраняя небольшую часть служебных данных системного вызова.
  • Ваша программа может быть немного проще с AIO, поскольку вам не нужен дополнительный поток для блокировки при чтении или записи.

Тем не менее, posix AIO имеет довольно неудобный интерфейс, например:

  • Единственное эффективное и хорошо поддерживаемое средство обратных вызовов событий - это сигналы, которые затрудняют его использование в библиотеке, поскольку это означает использование номеров сигналов из пространства имен глобальных процессов. Если ваша ОС не поддерживает сигналы в реальном времени, это также означает, что вам нужно выполнить все ваши выдающиеся запросы, чтобы выяснить, какой из них фактически завершен (например, для Mac OS X, а не для Linux). Улавливание сигналов в многопоточной среде также приводит к некоторым сложным ограничениям. Обычно вы не можете реагировать на событие внутри обработчика сигнала, но вам нужно поднять сигнал, записать в трубку или использовать signalfd() (в linux).
  • lio_suspend() имеет те же проблемы, что и select(), он не очень хорошо масштабируется с количеством заданий.
  • lio_listio(), поскольку реализовано довольно ограниченное количество заданий, которые вы можете пройти, и это не так просто, чтобы найти это ограничение переносимым образом. Вы должны вызвать sysconf (_SC_AIO_LISTIO_MAX), который может выйти из строя, и в этом случае вы можете использовать определение AIO_LISTIO_MAX, которое необязательно определено, но затем вы можете использовать 2, который определяется как гарантированный для поддержки.

Что касается реального приложения, использующего posix AIO, вы можете взглянуть на lighttpd (lighty), который также разместил измерение производительности при внедрении поддержки.

Большинство платформ posix теперь поддерживают posix AIO (Linux, BSD, Solaris, AIX, tru64). Windows поддерживает его через перекрывающиеся файлы ввода/вывода. Я понимаю, что только Solaris, Windows и Linux действительно поддерживают async. файловый ввод-вывод до самого драйвера, в то время как другие операционные системы эмулируют асинхронный режим. I/O с потоками ядра. Linux является исключением, его реализация posix AIO в glibc эмулирует асинхронные операции с потоками пользовательского уровня, тогда как собственный интерфейс ввода-вывода async (io_submit() и т.д.) По-настоящему асинхронен вплоть до драйвера, предполагая, что драйвер поддерживает его.

Я считаю довольно распространенным среди OSes не поддерживать posix AIO для любого fd, но ограничивать его обычными файлами.

Ответ 4

Существует aio_write - реализован в glibc; первый вызов функции aio_read или aio_write генерирует несколько потоков пользовательского режима, запросы aio_write или aio_read для этого потока, поток выполняет pread/pwrite, и когда он закончен, ответ отправляется обратно в заблокированный вызывающий поток.

Ther также является "реальным", поддерживаемым уровнем ядра (для этого требуется libaio, см. вызов io_submit http://linux.die.net/man/2/io_submit); для этого также нужен O_DIRECT (также может не поддерживаться всеми файловыми системами, но основные поддерживают его)

см. здесь:

http://lse.sourceforge.net/io/aio.html

http://linux.die.net/man/2/io_submit

Разница между POSIX AIO и libaio в Linux?