Каковы различия между poll и select?

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

2 ответов


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

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

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

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

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

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

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


на 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


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

предостережения select / poll против реакторов epoll в Twisted