Ответ 1
Для очень небольшого количества сокетов (конечно, зависит от вашего оборудования, но мы говорим о чем-то порядка 10 или менее), select может побить epoll в использовании памяти и скорости выполнения. Разумеется, для такого небольшого числа сокетов оба механизма настолько быстры, что на самом деле вы не заботитесь об этой разнице в подавляющем большинстве случаев.
Одно пояснение. Либо выборка, и шкала epoll линейно. Однако большая разница заключается в том, что API-интерфейсы, ориентированные на пользователя, имеют сложности, основанные на разных вещах. Стоимость вызова select
грубо совпадает со значением наивысшего пронумерованного файлового дескриптора, который вы передаете. Если вы выберете один fd, 100, то это примерно вдвое дороже, чем выбор на одном fd, 50. Добавление большего количества fds ниже самого высокого уровня не является достаточно бесплатным, поэтому на практике это немного сложнее, но это является хорошим первым приближением для большинства реализаций.
Стоимость epoll ближе к числу файловых дескрипторов, которые на самом деле имеют на них события. Если вы контролируете 200 дескрипторов файлов, но только 100 из них имеют на них события, то вы (очень грубо) платите за эти 100 активных файловых дескрипторов. Именно здесь epoll предлагает одно из своих основных преимуществ перед выбором. Если у вас есть тысяча клиентов, которые в основном не работают, тогда, когда вы используете select, вы все равно платите за каждую тысячу из них. Тем не менее, с epoll, похоже, что у вас есть только несколько - вы платите только за те, которые активны в любой момент времени.
Все это означает, что epoll приведет к меньшему использованию ЦП для большинства рабочих нагрузок. Что касается использования памяти, это немного подбрасывает. select
умеет представлять всю необходимую информацию очень компактным способом (один бит на дескриптор файла). И ограничение FD_SETSIZE (обычно 1024) на количество дескрипторов файлов, которое вы можете использовать с select
, означает, что вы никогда не будете тратить больше 128 байт для каждого из трех наборов fd, которые вы можете использовать с select
(чтение, запись, исключение). По сравнению с теми 384 байтами max, epoll - это своего рода свинья. Каждый файловый дескриптор представлен многобайтовой структурой. Однако, в абсолютном выражении, он все еще не собирается использовать много памяти. Вы можете представить огромное количество дескрипторов файлов в несколько десятков килобайт (примерно 20 тыс. На 1000 дескрипторов файлов, я думаю). И вы также можете указать, что вам нужно потратить все 384 этих байта с помощью select
, если вы хотите отслеживать только один дескриптор файла, но его значение равно 1024, ведь с epoll вы потратили бы только 20 байтов. Тем не менее, все эти цифры довольно малы, поэтому это не имеет большого значения.
И еще одно преимущество epoll, которое, возможно, вы уже знаете, что он не ограничивается файловыми дескрипторами FD_SETSIZE. Вы можете использовать его для мониторинга как можно большего количества дескрипторов файлов. И если у вас есть только один файловый дескриптор, но его значение больше, чем FD_SETSIZE, epoll тоже работает с этим, но select
не делает.
Случайно, я также недавно обнаружил один небольшой недостаток epoll
по сравнению с select
или poll
. Хотя ни один из этих трех API-интерфейсов не поддерживает нормальные файлы (т.е. Файлы в файловой системе), select
и poll
представляют эту нехватку поддержки, поскольку сообщают о таких дескрипторах, как всегда читаемые и всегда записываемые. Это делает их непригодными для каких-либо значимых типов неблокирующих файловых систем ввода/вывода, программа, которая использует select
или poll
и, случается, сталкивается с файловым дескриптором из файловой системы, по крайней мере продолжит работу (или если она не удастся, это не будет из-за select
или poll
), хотя это, возможно, не с лучшей производительностью.
С другой стороны, epoll
быстро завершится с ошибкой (EPERM
, по-видимому), когда будет предложено контролировать такой файловый дескриптор. Строго говоря, это вряд ли неверно. Это просто указывает на отсутствие поддержки в явном виде. Обычно я приветствую явные условия сбоя, но это недокументировано (насколько я могу судить) и приводит к полностью сломанному приложению, а не к тому, которое просто работает с потенциально ухудшенной производительностью.
На практике единственное место, где я видел это, - это взаимодействие с stdio. Пользователь может перенаправить stdin или stdout из/в обычный файл. В то время как ранее stdin и stdout были бы трубой, поддерживаемой epoll просто отлично, тогда она становится обычным файлом, и epoll не удается громко, нарушая приложение.