Каковы различия между опросом и выбором?

Я имею в виду стандарт POSIX select и poll API C API.

Ответ 1

Я думаю, что this отвечает на ваш вопрос:

От Ричарда Стивенса ([email protected]):

Основное отличие заключается в том, что select() fd_set - это бит-маска и поэтому имеет некоторый фиксированный размер. Было бы возможно, чтобы ядро не ограничивать этот размер, когда ядро ​​компилируется, что позволяет приложение для определения FD_SETSIZE на все, что захочет (в комментариях в заголовке системы подразумевается сегодня), но он требует больше работы. 4.4BSD-х ядро и функция библиотеки Solaris имеют этот предел. Но я см., что BSD/OS 2.1 теперь закодирована, чтобы избежать этого предела, поэтому выполнимый, просто небольшой вопрос программирования.:-) Кто-то должен подать Сообщение об ошибке Solaris сообщит об этом и посмотрит, исправлено ли это.

С помощью poll() пользователь должен выделить массив pollfd структуры и передать количество записей в этом массиве, так что нет фундаментального предела. Как отмечает Каспер, меньшее количество систем имеет опрос(), чем выберите, чтобы последний был более портативным. Кроме того, с оригинальным (SVR3), вы не можете установить дескриптор в -1, чтобы сообщить ядро, чтобы игнорировать запись в структуре pollfd, которая сделала это трудно удалить записи из массива; SVR4 оборачивается этим. Лично я всегда использую select() и редко poll(), потому что я переношу свои код для сред BSD. Кто-то может написать реализацию of poll(), который использует select() для этих сред, но я никогда не видел. Оба метода select() и poll() стандартизируются POSIX 1003.1g.

Октябрь 2017 Обновление:

Указанное выше электронное письмо не менее старое, чем в 2001 году; команда poll() теперь (2017) поддерживается во всех современных операционных системах, включая BSD. На самом деле, некоторые люди считают, что select() должно быть устаревшим. Мнения в сторону, проблемы переносимости вокруг poll() больше не беспокоят современные системы. Более того, epoll() с тех пор был разработан (вы можете прочитать справочную страницу) и продолжает расти в популярности.

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

Ответ 2

В вызове select() вы создаете три битмакса, чтобы отметить, какие сокеты и файловые дескрипторы вы хотите смотреть для чтения, записи и ошибок, а затем операционная система отмечает, какие из них фактически имеют какую-то деятельность; poll() вы создаете список идентификаторов дескрипторов, а операционная система помечает каждый из них тем случаем, что произошло.

Метод select() довольно неуклюж и неэффективен.

  • Обычно для процесса доступно более тысячи потенциальных файловых дескрипторов. Если у длительно работающего процесса открыто только несколько дескрипторов, но по крайней мере одному из них назначено большое число, тогда битмаска, переданная в select(), должна быть достаточно большой, чтобы разместить этот самый высокий дескриптор - так целые диапазоны сотен бит будет отключен, чтобы операционная система должна была пересекать любой вызов select(), чтобы обнаружить, что они не установлены.

  • Как только select() возвращается, вызывающий должен перебирать все три битмаски, чтобы определить, какие события имели место. В очень многих типичных приложениях только один или два дескриптора файлов получат новый трафик в любой момент, но все три битмаски должны быть прочитаны до конца, чтобы узнать, какие дескрипторы они есть.

  • Поскольку операционная система сигнализирует вам об активности, переписывая битмаски, они разрушаются и больше не помечены списком дескрипторов файлов, которые вы хотите прослушать. Вам либо нужно перестроить всю битовую маску из какого-либо другого списка, который вы храните в памяти, либо вам нужно сохранить дублируемую копию каждой битмаски и memcpy() блока данных поверх разрушенных битмаксов после каждого вызова select().

Таким образом, подход poll() работает намного лучше, потому что вы можете продолжать повторное использование той же структуры данных.

Фактически, poll() вдохновил еще один механизм в современных ядрах Linux: epoll(), который еще больше улучшает механизм, позволяющий еще один скачок в масштабируемости, поскольку сегодня серверы часто хотят обрабатывать десятки тысяч подключений на один раз. Это хорошее введение в усилия:

http://scotdoyle.com/python-epoll-howto.html

В то время как эта ссылка содержит несколько хороших графиков, показывающих преимущества epoll() (вы заметите, что select() к этому моменту считается настолько неэффективным и старомодным, что он даже не получает строку на этих графиках!):

http://lse.sourceforge.net/epoll/index.html


Обновление: Вот еще один вопрос, ответ на который дает еще более подробную информацию о различиях:

Предостережения по выбору/опросу против реакторов epoll в Twisted