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

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

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

Ответ 1

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

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

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


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

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

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

Ответ 2

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

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

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

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

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

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

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

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

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