Буферизованный асинхронный файловый ввод / вывод в Linux
Я ищу наиболее эффективный способ сделать асинхронный файловый ввод / вывод в Linux.
Реализация POSIX glibc использует потоки в пользовательском пространстве.
Нативный API-интерфейс ядра aio работает только с небуферизованными операциями, исправления для ядра для добавления поддержки буферизованных операций существуют, но им более 3 лет, и, похоже, никто не заботится об их интеграции в основную линию.
Я нашел множество других идей, концепций, патчей, которые допускают асинхронный ввод-вывод, хотя большинство из них есть в статьях, которым также>3 года. Что из этого действительно доступно в сегодняшнем ядре? Я читал о сервлетах, вызовах, вещах с потоками ядра и многих других вещах, которые сейчас даже не помню.
Каков наиболее эффективный способ сделать буферизованный асинхронный ввод / вывод файла в сегодняшнем ядре?
4 ответа
Если вы не хотите писать свой собственный пул потоков ввода-вывода, реализация glibc является приемлемым решением. Это на самом деле работает на удивление хорошо для чего-то, что работает полностью в пользовательском пространстве
В моем случае реализация ядра вообще не работает с буферизованным вводом-выводом (хотя я видел, как другие люди говорят обратное!). Что хорошо, если вы хотите читать огромные объемы данных через DMA, но, конечно, это отстой, если вы планируете использовать буферный кеш.
Также обратите внимание, что вызовы ядра AIO могут фактически блокироваться. Существует ограниченный размер буфера команд, и большие чтения разбиты на несколько меньших. Когда очередь заполнена, асинхронные команды выполняются синхронно. Сюрприз. Я столкнулся с этой проблемой год или два назад и не смог найти объяснения. Вопрос вокруг дал мне ответ "да, конечно, вот как это работает".
Из того, что я понял, "официальный" интерес к поддержке буферизованного AIO также не очень велик, несмотря на то, что несколько рабочих решений, кажется, доступны годами. Некоторые из аргументов, которые я прочитал, были такими: "Вы все равно не хотите использовать буферы", "Это никому не нужно" и "Большинство людей даже еще не использует epoll". Ну, хорошо... Мех.
Возможность получить epoll
До недавнего времени еще одной проблемой была сигнализация завершенной асинхронной операции, но в то же время это работает очень хорошо с помощью eventfd
,
Обратите внимание, что реализация glibc будет создавать потоки по требованию внутри __aio_enqueue_request
, Вероятно, это не так уж и страшно, поскольку порождение потоков уже не так уж и дорого, но об этом следует знать. Если ваше понимание запуска асинхронной операции "немедленно возвращается", то это предположение может быть неверным, поскольку сначала оно может порождать некоторые потоки.
РЕДАКТИРОВАТЬ:
Как примечание, в Windows существует ситуация, очень похожая на ситуацию в реализации glibc AIO, где предположение "немедленно вернуть" постановки в очередь асинхронной операции не соответствует действительности.
Если все данные, которые вы хотели прочитать, находятся в буферном кеше, Windows решит, что вместо этого выполнит запрос синхронно, потому что он все равно завершится немедленно. Это хорошо задокументировано и, по общему признанию, звучит великолепно. За исключением случаев, когда нужно скопировать несколько мегабайт, или если другой поток имеет сбои страниц или одновременно выполняет IO (таким образом, борясь за блокировку), "немедленно" может быть удивительно долгим временем - я видел "немедленные" времена 2-5 миллисекунд. Что не является проблемой в большинстве ситуаций, но, например, при ограничении времени кадра 16,66 мс, вы, вероятно, не хотите рисковать блокированием на 5 мс в случайные моменты времени. Таким образом, наивное предположение "может сделать асинхронный ввод-вывод из моего потока рендеринга без проблем, потому что асинхронный не блокирует" ошибочно.
Материал кажется старым - ну, он старый - потому что он существует уже давно и, хотя ни в коем случае не тривиально, хорошо понят. Решение, которое вы можете поднять, опубликовано в превосходной и беспримерной книге У. Ричарда Стивенса (читайте "Библию"). Книга - это редкое сокровище, которое ясно, кратко и полно: каждая страница дает реальную и непосредственную ценность:
Расширенное программирование в среде UNIX
Два других таких, также Стивенс, являются первыми двумя томами его коллекции сетевого программирования Unix:
Том 1: Сетевой API Сокетов (с Феннером и Рудоффом) и
Том 2: Межпроцессное взаимодействие
Я не могу представить себя без этих трех фундаментальных книг; Я ошеломлен, когда нахожу кого-то, кто не слышал о них.
Еще больше книг Стивена, столь же ценных:
(2021) Если ваше ядро Linux достаточно новое (по крайней мере, 5.1, но более новые ядра содержат улучшения), то это будет «наиболее эффективный способ асинхронного ввода/вывода файлов» *. Это относится как к буферизованному, так и к прямому вводу-выводу!
В видео Kernel Recipes 2019 «Быстрый ввод-вывод через io_uring» автор Йенс Эксбо демонстрирует буферизованный ввод-вывод через завершение почти в два раза быстрее, чем синхронный буферизованный ввод-вывод . Как отметил @Marenz, если вы не хотите, чтобы потоки пользовательского пространства были единственным способом выполнять буферизованный асинхронный ввод-вывод, потому что Linux AIO (он же
Кроме того, в статье «Современное хранилище достаточно быстрое». Глаубер Коста демонстрирует, как осторожное использование с асинхронным прямым вводом-выводом может повысить пропускную способность по сравнению с использованием для асинхронного буферизованного ввода-вывода на устройстве Optane. Глауберу потребовалась реализация упреждающего чтения в пользовательском пространстве (без которой буферизованный ввод-вывод был явным победителем), но улучшение было впечатляющим.
* Контекст этого ответа явно связан с хранилищем (в конце концов, было упомянуто слово «буферизованный»). Для сетевого ввода/вывода
Я не думаю, что реализация ядра Linux асинхронного файлового ввода-вывода действительно пригодна для использования, если вы не используете O_DIRECT, извините.
Здесь больше информации о текущем состоянии мира здесь: https://github.com/littledan/linux-aio. Он был обновлен в 2012 году кем-то, кто работал в Google.