Каково состояние асинхронного ввода / вывода POSIX (AIO)?

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

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

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

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

4 ответа

Решение

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

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

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

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

Эффективное выполнение сокетного ввода-вывода было решено с помощью портов kqueue, epoll, IO и тому подобного. Выполнение асинхронного файлового ввода-вывода является своего рода поздним выходом (кроме перекрывающегося ввода-вывода 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, но ограничить его обычными файлами.

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

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

Кроме того, он "настоящий" 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?

Другие вопросы по тегам