Каково состояние асинхронного ввода / вывода POSIX (AIO)? - PullRequest
91 голосов
/ 18 сентября 2008

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

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

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

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

Ответы [ 4 ]

69 голосов
/ 15 марта 2011

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

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

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

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

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

  • Ядро видит все дисковые операции ввода-вывода, а не только задания дисков ваших приложений, и может упорядочить их на глобальном уровне
  • Ядро (может) знает, где находится головка чтения диска, и может выбрать задания чтения, которые вы передаете ей в оптимальном порядке, чтобы переместить головку на кратчайшее расстояние
  • Ядро может использовать преимущества собственной очереди команд для дальнейшей оптимизации операций чтения
  • Вы можете выполнить больше операций чтения на системный вызов с помощью 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 действительно поддерживают асинхронность. файловый ввод-вывод вплоть до драйвера, тогда как другие операционные системы эмулируют асинхронный. Ввод / вывод с потоками ядра. Linux является исключением, его реализация posix AIO в glibc эмулирует асинхронные операции с потоками пользовательского уровня, в то время как его собственный асинхронный интерфейс ввода-вывода (io_submit () и т. Д.) Действительно асинхронен вплоть до драйвера, если драйвер поддерживает .

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

25 голосов
/ 18 сентября 2008

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

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

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

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

11 голосов
/ 26 октября 2012

Разработчик libtorrent предоставляет отчет по этому вопросу: http://blog.libtorrent.org/2012/10/asynchronous-disk-io/

2 голосов
/ 27 октября 2014

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

Ther также является «настоящим» aio - поддерживается уровнем ядра (для этого нужна 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?

...