Подтвердить что ты не робот

Почему epoll быстрее, чем выбрать?

Я видел много сравнений, которые говорят, что select должен пройти через список fd, и это медленно. Но почему epoll не должен это делать?

4b9b3361

Ответ 1

Там много дезинформации об этом, но настоящая причина такова:

Типичный сервер может иметь дело, скажем, с 200 соединениями. Он будет обслуживать каждое соединение, которое должно иметь данные, написанные или прочитанные, и тогда ему нужно будет ждать, пока не будет больше работы. Пока он ждет, его нужно прервать, если данные получены по любому из этих 200 подключений.

С select ядро ​​должно добавить процесс в 200 списков ожидания, по одному для каждого соединения. Для этого ему нужен "thunk", чтобы привязать процесс к списку ожидания. Когда процесс, наконец, просыпается, его нужно удалить из всех 200 списков ожидания, и все эти thunks необходимо освободить.

В отличие от epoll, у самого сокета epoll есть список ожидания. Процесс должен быть включен только в один список ожидания, используя только один бит. Когда процесс просыпается, его нужно удалить из одного списка ожидания, и только один thunk должен быть освобожден.

Чтобы быть ясным, с epoll сам сокет epoll должен быть присоединен к каждому из этих 200 подключений. Но это делается один раз для каждого соединения, когда оно принято в первую очередь. И это разрывается один раз, для каждого соединения, когда оно удаляется. Напротив, каждый вызов select, который блокирует, должен добавить процесс в каждую очередь ожидания для каждого контролируемого сокета.

По иронии судьбы, при select наибольшая стоимость исходит из проверки того, имели ли сокеты, у которых не было активности, какие-либо действия. С epoll нет необходимости проверять сокеты, у которых не было активности, потому что если у них была активность, они сообщали бы сокет epoll, когда это действие произошло. В некотором смысле, select проверяет каждый сокет каждый раз, когда вы вызываете select, чтобы увидеть, есть ли какая-либо активность в то время как epoll буровые установки, так что сама активность сокета уведомляет процесс.

Ответ 2

Основное различие между epoll и select заключается в том, что в select() список файловых дескрипторов для ожидания только существует в течение всего одного вызова select(), а вызывающая задача остается только в сокетах 'очереди ожидания в течение одного вызова. В epoll, с другой стороны, вы создаете один файловый дескриптор, который агрегирует события из нескольких других файловых дескрипторов, которые вы хотите подождать, и поэтому список отслеживаемых fd является долговечным, а задачи остаются в очереди ожидания сокетов в несколько системных вызовов. Кроме того, поскольку epoll fd можно использовать для нескольких задач, это больше не одна задача в очереди ожидания, а сама структура, содержащая еще одну очередь ожидания, содержащую все процессы, ожидающие в настоящее время на epoll fd. (В терминах реализации это абстрагируется очередями ожидания сокетов, содержащих указатель на функцию и указатель данных void* для передачи этой функции).

Итак, чтобы объяснить механику немного больше:

  • Файловый дескриптор epoll имеет закрытый struct eventpoll, который отслеживает, какие fd прикреплены к этому fd. struct eventpoll также имеет очередь ожидания, которая отслеживает все процессы, которые в настоящее время epoll_wait ing на этом fd. struct epoll также имеет список всех файловых дескрипторов, доступных в настоящее время для чтения или записи.
  • Когда вы добавляете дескриптор файла в epoll fd, используя epoll_ctl(), epoll добавляет struct eventpoll в эту очередь ожидания fd. Он также проверяет, готов ли fd к обработке и добавляет его в готовый список, если это так.
  • Когда вы ждете на epoll fd, используя epoll_wait, ядро ​​сначала проверяет готовый список и немедленно возвращается, если какие-либо дескрипторы файлов уже готовы. Если нет, он добавляет себя в одиночную очередь ожидания внутри struct eventpoll и переходит в режим сна.
  • Когда событие происходит в сокете epoll() ed, он вызывает обратный вызов epoll, который добавляет дескриптор файла в готовый список, а также пробуждает всех официантов, которые в настоящее время ждут этого struct eventpoll.

Очевидно, что требуется большая тщательная блокировка на struct eventpoll, а также различные списки и очереди ожидания, но это детализация реализации.

Важно отметить, что ни в какой точке выше я не описывал шаг, который пересекает все представляющие интерес файловые дескрипторы. epoll может избежать использования O (n) времени для операции, где n - количество дескрипторов файлов контролируется.