Книга: Разработка приложений в среде Linux. Второе издание
13.1.4. Сравнение poll() и select()
13.1.4. Сравнение poll()
и select()
Обладая одинаковой функциональностью, poll()
и select()
также имеют существенные отличия. Наиболее очевидным отличием является тайм-аут, поддерживающий миллисекундную точность для poll()
и микросекундную точность для select()
. В действительности же это отличие почти незначительно, поскольку ни один системный вызов не будет подготовлен с точностью до микросекунды.
Более важное отличие связано с производительностью. Интерфейс poll()
обладает несколькими свойствами, делающими его намного эффективнее, чем select()
.
1. При использовании select()
ядру необходимо проверить все файловые дескрипторы между 0
и numfds - 1
, чтобы убедиться, заинтересовано ли приложение в событиях ввода-вывода для этого файлового дескриптора. Для приложений с большим количеством открытых файлов это может привести к существенным затратам, поскольку ядро проверяет, какие именно файловые дескрипторы являются объектом интереса.
2. Набор файловых дескрипторов передается ядру как битовая карта для select()
и как список для poll()
. Сложные битовые операции, необходимые для проверки и установки структур данных fd_set
, менее эффективны, чем простые проверки, требуемые для struct pollfd
.
3. Поскольку ядро переписывает структуры данных, передаваемые select()
, приложение вынуждено сбрасывать эти структуры каждый раз перед вызовом select()
. С poll()
результаты ядра ограничены элементом revents
, что устраняет потребность в восстановлении структур данных после каждого вызова.
4. Использование структуры, основанной на множествах (например, fd_set
) не масштабируется по мере увеличения количества доступных процессу файловых дескрипторов. Поскольку ее размер статичен, а не динамичен (обратите внимание на отсутствие соответствующего макроса, например, FD_FREE
), она не может расширяться или сжиматься в соответствии с потребностями приложения (или возможностями ядра). В Linux максимальный файловый дескриптор, который можно установить в fd_set
, равен 1023. Если понадобится больший файловый дескриптор, select()
работать не будет.
Единственным преимуществом select()
перед poll()
является лучшая переносимость в старые системы. Поскольку небольшое количество таких реализаций все еще используется, следует применять select()
, прежде всего, для понимания и эксплуатации существующих кодовых баз.
Следующая короткая программа, подсчитывающая количество системных вызовов в секунду, демонстрирует, насколько poll()
эффективнее select()
.
1: /* select-vs-poll.с */
2:
3: #include <fcntl.h>
4: #include <stdio.h>
5: #include <sys/poll.h>
6: #include <sys/select.h>
7: #include <sys/signal.h>
8: #include <unistd.h>
9:
10: int gotAlarm;
11:
12: void catch(int sig) {
13: gotAlarm = 1;
14: }
15:
16: #define HIGH_FD 1000
17:
18: int main(int argc, const char ** argv) {
19: int devZero;
20: int count;
21: fd_set select Fds;
22: struct pollfd pollFds;
23:
24: devZero = open("/dev/zero", O_RDONLY);
25: dup2(devZero, HIGH_FD);
26:
27: /* с помощью signal выяснить, когда время истекло */
28: signal(SIGALRM, catch);
29:
30: gotAlarm =0;
31: count = 0;
32: alarm(1);
33: while (!gotAlarm) {
34: FD_ZERO(&selectFds);
35: FD_SET(HIGH_FD, &selectFds);
36:
37: select(HIGH_FD + 1, &selectFds, NULL, NULL, NULL);
38: count++;
39: }
40:
41: printf("Вызовов select() в секунду: %dn", count);
42:
43: pollFds.fd = HIGH_FD;
44: pollFds.events = POLLIN;
45: count = 0;
46: gotAlarm = 0;
47: alarm(1);
48: while (!gotAlarm) {
49: poll(&pollFds, 0, 0);
50: count++;
51: }
52:
53: printf("Вызовов poll() в секунду: %dn", count);
54:
55: return 0;
56: }
Здесь используется устройство /dev/zero
, предоставляющее бесконечное количество нулей, что обеспечивает немедленный возврат системных вызовов. Значение HIGH_FD
можно изменить, чтобы посмотреть, как деградирует select()
по мере роста значений файловых дескрипторов.
В определенной системе при не очень высоком значении HIGH_FD
, равном 2, программа показала, что ядро за секунду может обрабатывать в четыре раза больше вызовов poll()
, чем вызовов select()
. При увеличении HIGH_FD
до 1000 эффективность poll()
становится в 40 раз выше, чем у select()
.
- 13.1.6 Сравнение poll() и epoll
- 13.1.2. Мультиплексирование с помощью poll()
- 13.1.3. Мультиплексирование с помощью select()
- 8.1.4. Сравнение массивов
- 1. Оператор Select – базовый оператор языка структурированных запросов
- 4.2 Сравнение SAN и NAS
- Сравнение C# и C++
- 2.3.3 Selecting and Pasting
- Максимальное число дескрипторов для функции select
- Software Selection and Installation
- Window Selector
- 3.2. Сравнение операционных систем