Ответ 1
Если вы не хотите писать свой собственный пул потоков ввода-вывода, реализация glibc является приемлемым решением. Он действительно работает на удивление хорошо для чего-то, что полностью работает в пользовательском пространстве.
Реализация ядра не работает с буферизованным IO вообще в моем опыте (хотя я видел, как другие люди говорят об обратном!). Это нормально, если вы хотите читать огромные объемы данных через DMA, но, конечно, это отстойное время, если вы планируете использовать буферный кеш. Также обратите внимание, что вызовы ядра AIO могут фактически блокироваться. Существует командный буфер ограниченного размера, и большие чтения разбиваются на несколько более мелких. Когда очередь заполнена, асинхронные команды выполняются синхронно. Сюрприз. Я столкнулся с этой проблемой год или два назад и не смог найти объяснения. Отвечая на вопрос, я ответил: "Да, конечно, как это работает". Из того, что я понял, "официальный" интерес к поддержке буферизованного айо также не очень хорош, несмотря на то, что несколько рабочих решений, похоже, доступны в течение многих лет. Некоторые из аргументов, которые я читал, были в строках "вы не хотите использовать буферы в любом случае" и "никто этого не требует", и "большинство людей даже не используют epoll". Итак, хорошо... meh.
Возможность получить epoll
, сигнализируемую завершенной операцией async, была другой проблемой до недавнего времени, но в то же время это отлично работает с помощью eventfd
.
Обратите внимание, что реализация glibc фактически порождает потоки по требованию внутри __aio_enqueue_request
. Это, вероятно, не имеет большого значения, поскольку нерестовые потоки уже не так дороги, но об этом нужно знать. Если ваше понимание запуска асинхронной операции "немедленно возвращается", то это предположение может быть неверным, поскольку оно может сначала порождать некоторые потоки.
ИЗМЕНИТЬ:
В качестве побочного элемента под Windows существует очень похожая ситуация с тем, что реализовано в реализации glibc AIO, где предположение о "немедленном возврате" в очереди на асинхронную операцию неверно.
Если все данные, которые вы хотите прочитать, находятся в кеше буфера, Windows решит, что вместо этого он будет запускать запрос синхронно, потому что он все равно будет завершен. Это хорошо документировано и, по общему признанию, тоже звучит замечательно. За исключением случаев, когда есть несколько мегабайт для копирования или в случае, если другой поток имеет ошибки страницы или делает IO одновременно (таким образом, конкурируя за блокировку) "сразу" может быть неожиданно долгое время - я видел "немедленные" времена 2 -5 миллисекунд. Это не проблема в большинстве ситуаций, но, например, при ограничении времени кадра 16,66 мс, вы, вероятно, не хотите рисковать блокировкой в течение 5 мс в случайные моменты времени. Таким образом, наивное предположение о том, что "может сделать async IO из моего потока рендеринга без проблем, поскольку async не блокирует", является ошибочным.