Каковы различия между опросом и выбором?
Ответ 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