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() в секунду: %d ", 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() в секунду: %d ", count);
54:
55: return 0;
56: }
Здесь используется устройство /dev/zero, предоставляющее бесконечное количество нулей, что обеспечивает немедленный возврат системных вызовов. Значение HIGH_FD можно изменить, чтобы посмотреть, как деградирует select() по мере роста значений файловых дескрипторов.
В определенной системе при не очень высоком значении HIGH_FD, равном 2, программа показала, что ядро за секунду может обрабатывать в четыре раза больше вызовов poll(), чем вызовов select(). При увеличении HIGH_FD до 1000 эффективность poll() становится в 40 раз выше, чем у select().
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
13.1.6 Сравнение poll() и epoll
13.1.6 Сравнение poll() и epoll Методы poll() и epoll существенно отличаются; poll() хорошо стандартизован, но плохо масштабируется, в то время как epoll существует только в Linux, но очень хорошо масштабируется. Приложения, наблюдающие за небольшим количеством файловых дескрипторов и
Глава 6 Мультиплексирование ввода-вывода: функции select и poll
Глава 6 Мультиплексирование ввода-вывода: функции select и poll 6.1. Введение В разделе 5.12 мы видели, что наш TCP-клиент обрабатывает два входных потока одновременно: стандартный поток ввода и сокет TCP. Проблема, с которой мы столкнулись, состояла в том, что пока клиент был
6.10. Функция poll
6.10. Функция poll Функция poll появилась впервые в SVR3, и изначально ее применение ограничивалось потоковыми устройствами (STREAMS devices) (см. главу 31). В SVR4 это ограничение было снято, что позволило функции poll работать с любыми дескрипторами. Функция poll предоставляет
Интерфейс /dev/poll
Интерфейс /dev/poll В Solaris имеется специальный файл /dev/poll, с помощью которого можно опрашивать большее количество дескрипторов файлов. Проблема select и poll состоит в том, что список дескрипторов приходится передавать при каждом вызове. Устройство опроса поддерживает информацию
5.8.4 Оператор select
5.8.4 Оператор select Оператор select позволяет организовать интерактивное взаимодействие с пользователем. Он имеет следующий формат: select name [in word;] do list; doneВначале из шаблона word формируется список слов, соответствующих шаблону. Этот набор слов выводится в стандартный поток
Раздел Select
Раздел Select Но как же система узнает, какой из разделов ControlSetNNN необходимо использовать при обычной загрузке, какой нужно применять при загрузке последней удачной конфигурации, а какой вообще является испорченным? Именно для этих целей и предназначен раздел Select. Он
Оператор SELECT
Оператор SELECT Оператор SELECT осуществляет выборку из базы данных и имеет наиболее сложную структуру среди всех операторов языка SQL. Практически любой пользователь баз данных в состоянии написать простейший оператор SELECT типаSELECT * FROM PC;который осуществляет выборку всех
Команда SELECT
Команда SELECT SELECT * | { [ DISTINCT | ALL] <value expression>.,..} FROM { <table name> [ <alias> ] }.,.. [ WHERE <predicate>] [ GROUP BY { <column name> | <integer> }.,..] [ HAVING <predicate>] [ ORDERBY { <column name> | <integer> }.,..] [ { UNION [ALL]SELECT * | { [DISTINCT | ALL] < value expression >.,..} FROM { <table name> [<alias>]} .,.. [ WHERE <predicate> [ GROUP BY {
6.9. Использование select и poll с очередями сообщений
6.9. Использование select и poll с очередями сообщений Одним из недостатков очередей сообщений System V является то, что они идентифицируются не дескрипторами, а идентификаторами. Поэтому с ними нельзя использовать функции select и poll (глава 6 [24]). ПРИМЕЧАНИЕ На самом деле одна из
Оператор SELECT
Оператор SELECT Оператор SELECT является для клиентов фундаментальным методом поиска наборов данных в базе данных. Он имеет следующую основную форму:SELECT[FIRST (m)] [SKIP (n)] [[ALL] | DISTINCT]<список-столбцов> [, [имя-столбца] | выражение | константа ]AS имя-алиаса]FROM
Конструкция SELECT ... INTO
Конструкция SELECT ... INTO Конструкция SELECT ... INTO обычна для PSQL. Когда из таблицы запрашиваются значения, предложение INTO позволяет сохранить их в переменных - в локальных переменных или в выходных аргументах. В этой процедуре нет выходных параметров. Мы используем переменную ANY
Конструкция FOR SELECT ... DO
Конструкция FOR SELECT ... DO Для поиска множества строк в процедуре мы используем конструкцию FOR SELECT ... DO. Ее синтаксис:FOR<выражение-выбора>INTO <:переменная [, :переменная [, ...]] DO<составной-оператор>;<выражение-выбора> может быть любым запросом выбора, использующим