Говоря о разнице между select, poll и epoll

задняя часть

select, poll и epoll на самом деле являются методами мультиплексирования ввода-вывода в операционной системе.

select

Суть метода select заключается в поддержании массива файловых дескрипторов (fd) и реализации на его основе функции IO-мультиплексирования. Этот массив fd имеет ограничение по длине.В 32-битной системе максимальное значение равно 1024, а в 64-битной системе максимальное значение равно 2048. Эту конфигурацию можно назвать

cat /proc/sys/fs/file-max

смотреть

Вызывается метод select.Сначала fd_set нужно скопировать из пространства пользователя в пространство ядра, а затем ядро ​​использует механизм опроса (метод опроса этого механизма опроса не является методом мультиплексирования ввода-вывода, который можно найти в приложении) до тех пор, пока fd не станет активным или не истечет время ожидания, метод возвращает значение.

int select(int maxfdpl, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • Если возвращаемое значение равно -1, произошла ошибка
  • Если возвращаемое значение равно 0, это означает, что тайм-аут
  • Если возвращаемое значение положительное, это означает, что имеется n готовых fd.

После возврата метода select вам необходимо опросить fd_set, чтобы проверить fd, в котором произошло событие ввода-вывода. Таким образом, недостатки метода выбора очевидны:

  • Частое копирование fd_set в пространство пользователя и пространство ядра неэффективно.
  • Количество fd, которые может отслеживать один процесс, ограничено, будь то 1024 или 2048, что недостаточно для многих сценариев.
  • Реализовано на основе опроса, низкая эффективность

poll

int poll(struct pollfd fdarray[], nfds_t nfds, int timeout);

Poll по сути ничем не отличается от select.Он по-прежнему требует копирования структуры данных и по-прежнему реализован на основе опроса, но разница в том, что select использует массив fd, а poll поддерживает связный список, так что по идее, метод poll, есть больше не является ограничением на количество fd, которые может отслеживать один процесс. Но опрос, репликация и другие проблемы с выбором существуют, опрос все еще существует

epoll

epoll — это улучшение по сравнению с select и poll. Его основная идея основана на реализации, управляемой событиями, и ее несложно реализовать.Это регистрация функции обратного вызова для каждого fd.Когда на устройстве, соответствующем fd, происходит событие ввода-вывода, будет вызываться функция обратного вызова, и fd будет помещен в связанный список, а затем клиент извлекает каждый fd из связанного списка, чтобы достичь временной сложности O(1)

Фактически операция epoll соответствует трем функциям:epoll_create,epoll_ctr,epoll_wait

epoll_create

epoll_create эквивалентен созданию структуры данных, которая хранит fd в ядре. В методах select и poll ядро ​​не подготавливает структуру данных для fd для ее хранения, а просто и грубо копирует в нее массив или связанный список; в отличие от epoll, epoll_create создаст в ядре выделенный узел хранения fd. Красно-черное дерево epoll, если в будущем появятся новые узлы fd, они будут зарегистрированы на этом красно-черном дереве epoll.

epoll_ctr

Еще одно отличие состоит в том, что select и poll будут копировать все отслеживаемые fd в ядро ​​одновременно, а epoll отличается.Когда необходимо добавить новый fd, будет вызываться epoll_ctr для регистрации callback-функции для этого fd.Затем зарегистрируйте fd в красно-черное дерево ядра. Когда устройство, соответствующее fd, будет активным, будет вызвана функция обратного вызова для fd, и узел будет сохранен в списке готовности. Это также решает проблему копирования между пространством ядра и пространством пользователя.

epoll_wait

Практика epoll_wait тоже очень проста, по сути, он напрямую берет узел из готового списка, что также решает проблему опроса, а временная сложность становится O(1)

Итак, в целом преимущества epoll:

  • Максимальное количество одновременных подключений не ограничено, оно намного превышает 1024 или 2048. (Ходят слухи, что 10W порты можно мониторить на 1G памяти)
  • Эффективность становится выше. epoll основан на реализации, управляемой событиями, и его эффективность не будет снижаться по мере увеличения количества fd.
  • Уменьшить количество копий памяти

Горизонтальный триггер и триггер по краю

Понимается просто

Горизонтальное срабатывание означает, что до тех пор, пока выполняются условия, соответствующее событие всегда будет генерироваться. Поэтому, если условие выполнено, но не обработано, оно всегда будет уведомлено.

Запуск по границе означает, что после выполнения условия соответствующее событие будет запущено только один раз, независимо от того, обработано оно или нет, оно будет запущено только один раз.

Для выбора и опроса триггеры являются горизонтальными триггерами. И у epoll есть два режима: EPOLLLT и EPOLLET.

  • EPOLLLT (состояние по умолчанию): то есть горизонтальный триггер. В этом режиме, пока в fd есть данные для чтения, функция epoll_wait вернет fd.
  • EPOLLET (высокоскоростной режим): то есть срабатывает по фронту. В этом режиме, когда на отслеживаемый fd происходит событие readable и writeable, epoll_wait будет уведомлять программу о чтении и записи.Если это чтение и запись не прочитает все данные, или даже не обработает их, то в следующий раз epoll_wait называется , то fd получено не будет. Эта эффективность выше, чем у горизонтального срабатывания, система не будет завалена большим количеством фд, которые не интересуют программы.

Суммировать:

  • выбор и опрос реализованы на основе опроса, копирование fd_set из пользовательского пространства в пространство ядра, а затем позволяет пространству ядра опрашивать с помощью механизма опроса. space), а затем клиент опрашивает каждый fd, чтобы найти тот fd, который имеет событие ввода-вывода.
  • epoll основан на реализации, управляемой событиями.Добавление нового fd вызовет функцию epoll_ctr, чтобы зарегистрировать функцию обратного вызова для fd, а затем зарегистрировать узел fd в красно-черном дереве epoll в ядре.Когда происходит событие ввода-вывода, будет вызвана функция обратного вызова, чтобы поместить узел fd в список готовых, и функция epoll_wait фактически получит эти fd из списка готовых.
  • epoll делится на EPOLLLT (горизонтальный триггер, состояние по умолчанию) и EPOLLET (триггер по фронту, высокая эффективность)
  • epoll не является лучшим во всех случаях, например, когда число fds невелико, epoll не обязательно лучше, чем select и poll.