User Tools

Site Tools


Kqueue vs. Epool

“Я просто оставлю это здесь” © =)

Date: Fri, 17 Jan 2003 14:12:55 +0500
From: Igor Sysoev <is at rambler-co.ru>
Newsgroups: ftn.ru.linux
Subject: Различия kqueue (FreeBSD) и epoll (Linux)

IS>> Hу почему, можно обойтись, почему нельзя ?  Можно обойтись
IS>> select()ом или poll()ом. Только вот процессор они будут жрать при
IS>> тысячах дескрипторах. Можно ещё сделать всякие хинтинги для
IS>> poll()а. Hо и это не спасает процессор. Тогда можно изобрести
IS>> /dev/poll или, скажем, /dev/epoll. А потом превратить /dev/epoll
IS>> в системные вызовы epoll_*. Можно ещё сделать rtsignals, только
IS>> они почему-то имеют тенденцию переполняться. Можно сделать
IS>> дешёвые трэды (в смысле оверхеда), но всё равно процессор будет
IS>> тратить всё свое на переключение между ними.
 
IS>> А ещё можно подумать передней головой и сделать kqueue.
 
> ну так чем epoll_* не устраивает?
> не позволяет мониторить child exit/etc? а надо?

Hет, я, конечно, понимаю, что это такой дискуссионный приём - взять
незначительную фичу и выдать её за единственное отличие, но продвинутых
товарищей этим не испугаешь. Продвинутые товарищи могут дать развёрнутый
и подкованный ответ.

Hачнём с механизма добавления и удаления событий.
Допустим, я хочу добавить сообщение о готовности на чтение и на запись
файлового дескриптора. А потом я хочу удалить сообщение о записи.
В kqueue для этого нужно добавить два события - EVFILT_READ и EVFILE_WRITE
с флагом EV_ADD. Для удаления потом достаточно добавить событие
EVFILT_WRITE с флагом EV_DELETE.
В epoll добавление делается один событием - POLLIN|POLLOUT.
А вот удаление - двумя - POLLREMOVE, а затем снова добавить чтение POLLIN.
Буккиппинг в юзер-спэйс от этого усложняется, если мы, конечно, хотим делать
его эффективно, а не в лоб.

Перейдём к нотификации. kqueue поддерживает три вида нотификации:
1. Обычный, когда событие сообщает о себе до тех пор, пока его
   не сбросят - прочитают, запишут и т.д.;
2. EV_ONESHOT, событие сообщает о себе только один раз, после чего оно
   само удаляется;
3. EV_CLEAR, событие сообщает о себе лишь при изменении состояния,
   например, пришли новые байты, затем пришли ещё новые байты.
   То есть, оно само сбрасывается.

epoll поддерживает только третий вариант.
/dev/poll, для особо любознательных, - только первый.

Hе скажу, требует ли epoll, как /dev/poll, обязательного удаления
дескриптора перед закрытием, но kqueue этого точно не требует.

Плюс epoll я вижу только в одном - он может получать нотификации
через mmap()нутую память.

Всё, на этом все фичи epoll заканчиваются.

Для файловых дескрипторов kqueue выставляет флаг конца файла, количество
оставшихся байт и код ошибки. Все эти мелкие радости позволяют
уменьшить число сисколов. Hапример, байты ещё есть и стоит конец
файла - делаем read(), получаем байты. Байтов уже нет и стоит конец
файла, тогда делать read(), чтобы прочитать ноль, делать не нужно.
Стоит код ошибки, тогда делать read(), чтобы получить ту же ошибку,
делать не нужно.

У всех событий есть opaque data, в котором может быть указатель или число -
очень удобно для user-lavel book keeping.

Помимо обычных дескрипторов kqueue позволяет получать нотификации
о завершении aio операций (эй, в Линуксе знают о aio операциях !?!),
об изменения мета-данных файла на диске, от таймеров, сигналов,
и процессов, в том числе и упомянутого в качестве дискуссионного приёма
child exit/etc.

Всё это, прошу заметить, в одной точке ожидания, позволяющей избежать
разнообразных race conditions и оверхедов, связанных с кодом, который должен
решать проблему race conditions.

Hу и наконец, в kqueue можно добавлять новые типы событий в разумных пределах.
А вот epoll связан по рукам и ногам struct pollfd.


-- 
Игорь Сысоев
http://sysoev.ru