Каковы различия между опросом и выбором? - PullRequest
151 голосов
/ 09 июня 2009

Я имею в виду стандарт POSIX выбор и опрос вызовов API системы C.

Ответы [ 2 ]

217 голосов
/ 17 октября 2010

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

Метод select() довольно громоздкий и неэффективный.

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

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

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

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

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

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

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

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


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

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

78 голосов
/ 09 июня 2009

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

От Ричарда Стивенса (rstevens@noao.edu):

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...