Рассмотрим приложение, которое связано с ЦП, но также имеет высокопроизводительные требования ввода-вывода.
Я сравниваю Linux файл ввода/вывода с Windows, и я не вижу, как epoll поможет программе Linux вообще. Ядро скажет мне, что дескриптор файла "готов к чтению", но мне все равно нужно вызвать функцию блокировки read(), чтобы получить мои данные, и если я хочу читать мегабайты, довольно ясно, что это будет заблокировано.
В Windows я могу создать дескриптор файла с набором OVERLAPPED, а затем использовать неблокирующий ввод-вывод и получить уведомление о завершении ввода-вывода и использовать данные из этой функции завершения. Мне нужно потратить время на настенные часы на уровне приложения, ожидая данных, а это значит, что я могу точно настроить количество потоков на мое количество ядер и получить 100% эффективное использование процессора.
Если мне нужно эмулировать асинхронный ввод-вывод в Linux, тогда мне нужно выделить некоторое количество потоков для этого, и эти потоки потратят немного времени на выполнение CPU, и много времени блокирует I/O, плюс в обмене сообщениями на/из этих потоков будут накладные расходы. Таким образом, я либо переподписываю, либо недоиспользую свои ядра процессора.
Я посмотрел на mmap() + madvise() (WILLNEED) как "асинхронный ввод-вывод" плохой человек ", но он все еще не проходит весь путь, потому что я не могу получить уведомление, когда это будет сделано - - Я должен" угадать ", и если я думаю" неправильно", я закончу блокирование доступа к памяти, ожидая, что данные будут поступать с диска.
Linux, похоже, запускает асинхронные операции ввода-вывода в io_submit, и, похоже, также имеет реализацию POSIX aio для пользовательского пространства, но на некоторое время это было так, и я не знаю никого, кто ручался бы за эти системы для критически важных высокопроизводительных приложений.
Модель Windows работает примерно так:
- Выполните асинхронную операцию.
- Свяжите асинхронную операцию с конкретным портом завершения ввода-вывода.
- Дождитесь завершения операций над этим портом
- Когда ввод-вывод завершен, поток, ожидающий от порта, блокируется и возвращает ссылку на ожидающую операцию ввода-вывода.
Шаги 1/2 обычно выполняются как одна вещь. Шаги 3/4 обычно выполняются с пулом рабочих потоков, а не (обязательно) тот же поток, что и проблемы ввода-вывода. Эта модель несколько похожа на модель, предоставляемую boost:: asio, за исключением boost:: asio фактически не дает вам асинхронного ввода-вывода на основе блоков (диска).
Разница с epoll в Linux заключается в том, что на шаге 4 никаких операций ввода-вывода еще не произошло - он поднимает шаг 1 после шага 4, который является "обратным", если вы точно знаете, что вам нужно.
Запросив большое количество встроенных, настольных и серверных операционных систем, я могу сказать, что эта модель асинхронного ввода-вывода очень полезна для определенных видов программ. Это также очень высокая пропускная способность и низкий расход. Я думаю, что это один из оставшихся реальных недостатков модели ввода-вывода Linux на уровне API.