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

Ответы:

90

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

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

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

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

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

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

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

akappa
источник
15
Когда был написан ответ Стивенса? Применим ли комментарий о том, что poll () недоступен на BSD? MacOS X (который частично основан на BSD) имеет функцию poll (), и стандарт POSIX (POSIX 2008) требует этого.
Джонатан Леффлер
12
Рич Стивенс скончался в сентябре 1999 года, поэтому ответ должен быть старше этого. Он упоминает о новых изменениях в BSD / OS 2.1, которая была выпущена в январе 1996 года, так что, вероятно, примерно в то время.
alanc
2
Я не верю этому. Ответ опубликован 5 лет назад, я наткнулся на него, оставил его открытым в браузере. Уже на следующий день автор редактирует и улучшает ответ. ТАК уведомляет меня об обновлении на странице, используя AJAX / websocket. Вот почему ТАК великолепен
Стивен Лу
9
@StevenLu Да, но, к сожалению, нет слов о том, использует ли AJAX / websocket selectили poll:(
Кристофер Шульц,
> Кто-то может написать реализацию poll (), которая использует select () для этих сред, но я никогда не видел ее. Ява так делает ;-)
Сергей Машков
229

При 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

Брэндон Роудс
источник
1
И +1 за ссылку на пример использования epoll в python - похоже, там есть несколько интересных примеров, и мне придется их опробовать ...
Аллен Джордж
+1 за объяснение ответа; -1 за упоминание epoll, но не kqueue
Good Person
Этот ответ звучит так, как будто epoll всегда предпочтительнее
user3467349
0

Оба они медленные и в основном одинаковые , но разные по размеру и некоторым функциям!

Когда вы пишете итератор, вам нужно копировать множество selectкаждый раз! Пока pollисправлена ​​такая проблема, чтобы иметь красивый код. Другое отличие заключается в том, что pollпо умолчанию может обрабатывать более 1024 файловых дескрипторов (FD). pollможет обрабатывать различные события, чтобы сделать программу более читабельной, вместо того, чтобы иметь много переменных для обработки такого рода работы. Операции в pollи selectлинейные и медленные из-за большого количества проверок.

Амир Фо
источник