Я маю в виду стандартний POSIX добірних і опитування викликів API системи C.
Я маю в виду стандартний POSIX добірних і опитування викликів API системи C.
Відповіді:
Я думаю, що це відповідає на ваше запитання:
Від Річарда Стівенса (rstevens@noao.edu):
Основна відмінність полягає в тому, що fd_set select () є бітною маскою і тому має деякий фіксований розмір. Ядро могло б не обмежувати цей розмір під час компіляції ядра, що дозволяє додатку визначати FD_SETSIZE на все, що хоче (як випливають із коментарів у заголовку системи сьогодні), але це потребує більшої роботи. Це ядро 4.4BSD і функція бібліотеки Solaris мають це обмеження. Але я бачу, що BSD / OS 2.1 тепер були закодовані, щоб уникнути цього обмеження, тому це можливо, лише невелика справа програмування. :-) Хтось повинен подати звіт про помилку Solaris про це і побачити, чи він коли-небудь виправляється.
Однак, опитуючи (), користувач повинен виділити масив структур pollfd та пропустити кількість записів у цьому масиві, тому немає принципового обмеження. Як зазначає Каспер, менша кількість систем має опитування (), ніж вибір, тому остання є більш портативною. Крім того, з оригінальними реалізаціями (SVR3) ви не змогли встановити дескриптор до -1, щоб сказати ядру ігнорувати запис у структурі pollfd, що ускладнило видалення записів з масиву; SVR4 обходить це. Особисто я завжди використовую select () і рідко запитую (), тому що я також портую свій код до BSD-середовищ. Хтось може написати реалізацію опитування (), яке використовує select (), для цих середовищ, але я жодного разу не бачив цього. Як select (), так і опитування () стандартизуються POSIX 1003.1g.
Електронна пошта, на яку було посилатися вище, принаймні стара в 2001 році; poll()
команда зараз (2017) підтримується у всіх сучасних операційних систем , в тому числі - BSD. Насправді, деякі люди вважають, що це select()
слід застаріти . Думки осторонь, питання переносимості навколо poll()
вже не хвилюють сучасні системи. Крім того, epoll()
вона була розроблена (ви можете прочитати сторінку людини ) і продовжує наростати популярність.
Для сучасної розробки ви, мабуть, не хочете використовувати select()
, хоча в цьому явно нічого поганого немає. poll()
, і це більш сучасна еволюція epoll()
, забезпечують ті ж характеристики (і більше), що і select()
не страждаючи від обмежень, які в них містяться.
select
або poll
:(
У 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
Оновлення: Ось ще одне запитання щодо переповнення стека, відповідь якого дає ще більш детальну інформацію про відмінності:
Порізи реакторів вибору / опитування проти епольних реакторів у крученому
Обидва вони повільні і здебільшого однакові , але різні за розміром і якимись особливостями!
Коли ви пишете ітератор, вам потрібно select
кожного разу копіювати набір ! Хоча poll
вирішили подібну проблему, щоб мати гарний код. Ще одна відмінність полягає в тому, що poll
за замовчуванням може працювати більше 1024 дескрипторів файлів (FD). poll
може обробляти різні події, щоб зробити програму більш зрозумілою, замість того, щоб мати багато змінних для обробки подібних завдань. Операції в poll
і select
лінійні, і повільні, оскільки багато перевірок.