Почему именно ePoll масштабируется лучше, чем опрос? - PullRequest
11 голосов
/ 22 марта 2011

Короткий вопрос, но для меня его трудно понять.

Почему именно ePoll масштабируется лучше, чем опрос?

Ответы [ 2 ]

16 голосов
/ 17 января 2012

Хотя причина Дэймона верна для необычного случая, когда вы никогда не блокируете сокет, в типичных реальных программах причина совершенно иная. Типичная программа выглядит так:

1) Сделайте всю работу, которую мы можем сделать сейчас.

2) Проверьте, нужно ли обслуживание каких-либо сетевых подключений, заблокировав, если нечего делать.

3) Обслуживайте любые обнаруженные сетевые подключения.

4) Перейти к шагу 1.

Как правило, поскольку вы только что выполнили всю работу, которую можете сделать, когда вы переходите к шагу 2, вам нечем заняться. Так что вам придется немного подождать. Теперь представьте, что вас интересуют 800 сокетов. Ядро должно поставить очередь ожидания для каждого из этих 800 сокетов. И спустя долю секунды, когда данные поступают в один из этих 800 сокетов, ядро ​​должно удалить вас из этих 800 очередей ожидания. Чтобы поместить задачу в очередь ожидания, требуется создать 'thunk', чтобы связать эту задачу с этой очередью ожидания. Хорошие оптимизации невозможны, потому что ядро ​​не знает, какие 800 сокетов вы будете ждать.

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

Когда в сокете есть активность, ядро ​​обрабатывает ее в задаче, которая обнаруживает активность. Когда вы ждете, ядро ​​уже знает, есть ли обнаруженное событие, и ядру нужно только поставить вас в одну очередь ожидания. Когда вы просыпаетесь, вам нужно только удалить вас из этой очереди.

Так что копирование - это не столько убийство с select или poll, сколько факт, что ядру приходится манипулировать огромным количеством очередей ожидания при каждой операции блокировки.

14 голосов
/ 22 марта 2011

Системный вызов poll должен каждый раз копировать ваш список файловых дескрипторов в ядро. Это происходит только один раз с epoll_ctl, но не каждый раз, когда вы звоните epoll_wait.

Кроме того, epoll_wait равно O(1) в отношении количества просмотренных дескрипторов 1 , что означает, что не имеет значения, ожидаете ли вы один дескриптор или 5000 или 50 000 дескрипторов. poll, будучи более эффективным, чем select, все равно должен каждый раз проходить по списку (то есть O(N) в отношении количества дескрипторов).

И, наконец, epoll может, в дополнение к «нормальному» режиму, работать в режиме «запуска по фронту», что означает, что ядру не нужно отслеживать, сколько данных вы прочитали после того, как вам сообщили о готовности. Этот режим труднее понять, но несколько эффективнее.

<ч /> 1 Как правильно указал Дэвид Шварц, epoll_wait, конечно, все еще O(N) в отношении событий, которые происходят . Едва ли может быть иначе, с любым интерфейсом. Если в отслеживаемом дескрипторе происходят события N , то приложению необходимо получать N уведомлений и делать N «вещей» для реакции о том, что происходит.
Это снова немного, но принципиально не отличается в режиме запуска по фронту, где вы на самом деле получаете M событий с M <= N. В режиме запуска по фронту, когда одно и то же событие (скажем, POLLIN) происходит несколько раз, вы, вероятно, получите меньше уведомлений, возможно, только одно. Однако это не сильно меняет представление о биг-О как таковом.

Однако epoll_wait не зависит от количества просмотренных дескрипторов . В предположении, что он используется намеченным, «нормальным» способом (то есть многими дескрипторами, немногими событиями), это то, что действительно имеет значение, и здесь это действительно O(1).

В качестве аналогии вы можете подумать о хеш-таблице. Хеш-таблица обращается к своему содержимому в O(1), но можно утверждать, что вычисление хеша на самом деле O(N) в отношении длины ключа. Технически это абсолютно правильно, и, вероятно, существуют случаи, когда это является проблемой, однако для большинства людей это просто не имеет значения.

...