Для очень небольшого количества сокетов (конечно, зависит от вашего оборудования, но мы говорим о чем-то порядка 10 или меньше), select может превзойти epoll в использовании памяти и скорости выполнения. Конечно, для такого небольшого количества сокетов оба механизма настолько быстры, что в большинстве случаев вас не волнует это различие.
Одно уточнение. И выберите, и эполл масштабировать линейно. Однако большая разница заключается в том, что API, ориентированные на пользовательское пространство, имеют сложности, основанные на разных вещах. Стоимость вызова select
примерно соответствует значению дескриптора файла с наибольшим номером, который вы передаете. Если вы выберете один fd, 100, то это примерно в два раза дороже, чем выбор одного fd, 50. Добавление большего количества fds ниже самого высокого уровня не совсем бесплатно, так что на практике это немного сложнее, чем это, но это является хорошим первым приближением для большинства реализаций.
Стоимость epoll ближе к количеству файловых дескрипторов, в которых действительно есть события. Если вы отслеживаете 200 файловых дескрипторов, но только у 100 из них есть события, то вы (очень грубо) платите только за эти 100 активных файловых дескрипторов. Именно здесь epoll имеет тенденцию предлагать одно из основных преимуществ по сравнению с select. Если у вас есть тысяча клиентов, которые в основном бездействуют, то при использовании select вы все равно платите за все тысячу из них. Однако в случае epoll у вас есть только несколько - вы платите только за те, которые активны в любой момент времени.
Все это означает, что epoll приведет к меньшему использованию процессора для большинства рабочих нагрузок. Что касается использования памяти, это немного сложно. select
удается представить всю необходимую информацию в очень компактном виде (один бит на дескриптор файла). А ограничение FD_SETSIZE (обычно 1024) на количество файловых дескрипторов, которые вы можете использовать с select
, означает, что вы никогда не потратите более 128 байтов на каждый из трех наборов fd, которые вы можете использовать с select
(чтение, запись, исключение). По сравнению с этими 384 байтами максимум, 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 были бы конвейером - он прекрасно поддерживал epoll - тогда он становился обычным файлом и epoll громко терпел неудачу, ломая приложение.