Jakie są różnice między ankietą a wyborem?

Odpowiedzi:

90

Myślę, że to odpowiada na twoje pytanie:

Od Richarda Stevensa ([email protected]):

Podstawowa różnica polega na tym, że fd_set funkcji select () jest maską bitową i dlatego ma pewien stały rozmiar. Byłoby możliwe, aby jądro nie ograniczało tego rozmiaru podczas kompilacji jądra, pozwalając aplikacji na zdefiniowanie FD_SETSIZE do tego, czego chce (jak sugerują dzisiejsze komentarze w nagłówku systemu), ale wymaga to więcej pracy. Jądro 4.4BSD i funkcja biblioteczna Solaris mają to ograniczenie. Ale widzę, że BSD / OS 2.1 został teraz zakodowany, aby uniknąć tego ograniczenia, więc jest to wykonalne, tylko mała kwestia programowania. :-) Ktoś powinien zgłosić błąd w Solarisie i sprawdzić, czy kiedykolwiek zostanie naprawiony.

Jednak w przypadku funkcji poll () użytkownik musi przydzielić tablicę struktur pollfd i przekazać liczbę wpisów w tej tablicy, więc nie ma podstawowego ograniczenia. Jak zauważa Casper, mniej systemów ma funkcję poll () niż select, więc ta ostatnia jest bardziej przenośna. Ponadto w oryginalnych implementacjach (SVR3) nie można było ustawić deskryptora na -1, aby nakazać jądru ignorowanie wpisu w strukturze pollfd, co utrudniało usuwanie wpisów z tablicy; SVR4 omija ten problem. Osobiście zawsze używam select () i rzadko poll (), ponieważ przenoszę swój kod również do środowisk BSD. Ktoś mógłby napisać implementację poll (), która używa funkcji select () dla tych środowisk, ale nigdy takiej nie widziałem. Zarówno select (), jak i poll () są standaryzowane przez POSIX 1003.1g.

Aktualizacja z października 2017 r .:

Adres e-mail, o którym mowa powyżej, ma co najmniej rok 2001; poll()komenda jest teraz (2017) obsługiwany we wszystkich nowoczesnych systemów operacyjnych - w tym BSD. W rzeczywistości niektórzy uważają, że select() powinno to zostać wycofane . Pomijając opinie, problemy z przenośnością poll()nie dotyczą już nowoczesnych systemów. Co więcej, epoll()od tego czasu został opracowany (możesz przeczytać stronę podręcznika ) i nadal zyskuje na popularności.

W przypadku współczesnego programowania prawdopodobnie nie chcesz go używać select(), chociaż nie ma w tym nic złego. poll()i jest to bardziej nowoczesna ewolucja epoll(), zapewnia te same funkcje (i więcej), co select()bez cierpienia z powodu ograniczeń.

akappa
źródło
15
Kiedy napisano odpowiedź Stevensa? Czy komentarz o niedostępności funkcji poll () na BSD nadal obowiązuje? MacOS X (który jest częściowo oparty na BSD) ma funkcję poll (), a standard POSIX (POSIX 2008) tego wymaga.
Jonathan Leffler
12
Rich Stevens zmarł we wrześniu 1999 roku, więc odpowiedź musi być starsza. Wspomina o nowej zmianie w BSD / OS 2.1, która została wydana w styczniu 1996 roku, więc prawdopodobnie w tym czasie.
alanc
2
Nie wierzę w to. Odpowiedź wysłana 5 lat temu, natknąłem się na nią, zostaw ją otwartą w przeglądarce. Już następnego dnia autor redaguje i poprawia odpowiedź. SO powiadamia mnie o aktualizacji na stronie za pomocą AJAX / websocket. dlatego SO jest świetny
Steven Lu
9
@StevenLu Tak, ale niestety nie ma informacji o tym, czy używa AJAX / websocket, selectczy poll:(
Christopher Schultz
> Ktoś mógłby napisać implementację poll (), która używa funkcji select () dla tych środowisk, ale nigdy takiej nie widziałem. Java to robi ;-)
Sergey Mashkov
229

select()Wezwanie musi utworzyć trzy bitmasks do znaku, który gniazd i deskryptory plików, które chcesz oglądać do czytania, pisania i błędy, a następnie oznaczeniami system operacyjny, który z nich w rzeczywistości miały jakąś aktywność; poll()czy utworzyłeś listę identyfikatorów deskryptorów, a system operacyjny oznacza każdy z nich rodzajem zdarzenia, które miało miejsce.

select()Metoda jest raczej niezgrabne i nieefektywne.

  1. Zazwyczaj proces ma do dyspozycji ponad tysiąc potencjalnych deskryptorów plików. Jeśli długotrwały proces ma otwartych tylko kilka deskryptorów, ale przynajmniej jednemu z nich przypisano wysoką liczbę, wówczas przekazana maska ​​bitowa select()musi być wystarczająco duża, aby pomieścić ten najwyższy deskryptor - więc całe zakresy setek bitów będą nie przejmuj się tym, że system operacyjny musi przechodzić przez pętlę przy każdym select()wywołaniu tylko po to, aby odkryć, że nie są one ustawione.

  2. Po select()powrocie obiekt wywołujący musi wykonać pętlę po wszystkich trzech maskach bitowych, aby określić, jakie zdarzenia miały miejsce. W bardzo wielu typowych aplikacjach tylko jeden lub dwa deskryptory plików otrzymają nowy ruch w dowolnym momencie, jednak wszystkie trzy maski bitowe muszą zostać przeczytane do końca, aby odkryć, które to są deskryptory.

  3. Ponieważ system operacyjny sygnalizuje aktywność, przepisując maski bitowe, są one zniszczone i nie są już oznaczone listą deskryptorów plików, których chcesz słuchać. Musisz albo odbudować całą maskę bitową z innej listy, którą trzymasz w pamięci, albo musisz zachować zduplikowaną kopię każdej maski bitowej i memcpy()bloku danych na zrujnowanych maskach bitowych po każdym select()wywołaniu.

Tak więc poll()podejście to działa znacznie lepiej, ponieważ możesz nadal używać tej samej struktury danych.

W rzeczywistości poll()zainspirował kolejny mechanizm w nowoczesnych jądrach Linuksa: epoll()który jeszcze bardziej ulepsza mechanizm, umożliwiając kolejny skok skalowalności, ponieważ dzisiejsze serwery często chcą obsługiwać dziesiątki tysięcy połączeń naraz. To jest dobre wprowadzenie do tego wysiłku:

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

Chociaż ten link ma kilka ładnych wykresów pokazujących korzyści epoll()(zauważysz, że select()w tym momencie jest uważany za tak nieefektywny i staromodny, że nawet nie ma linii na tych wykresach!):

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


Aktualizacja: Oto kolejne pytanie dotyczące przepełnienia stosu, którego odpowiedź zawiera jeszcze więcej szczegółów na temat różnic:

Ostrzeżenia dotyczące reaktorów typu select / poll w porównaniu z reaktorami epoll w Twisted

Brandon Rhodes
źródło
1
I +1 za link do przykładu użycia epoll w Pythonie - wygląda na to, że jest tam kilka interesujących przykładów i będę musiał je wypróbować ...
Allen George
+1 za wyjaśnienie odpowiedzi; -1 za wzmiankę o epollu, ale nie o kqueue
Good Person,
Ta odpowiedź brzmi tak, jakby epoll był zawsze lepszy
user3467349
0

Oba są powolne iw większości takie same , ale różnią się rozmiarem i pewnymi funkcjami!

Kiedy piszesz iterator, za selectkażdym razem musisz skopiować zestaw ! Chociaż pollrozwiązał ten problem, aby mieć piękny kod. Inną różnicą jest to, że polldomyślnie obsługuje więcej niż 1024 deskryptory plików (FD). pollmoże obsługiwać różne zdarzenia, aby uczynić program bardziej czytelnym, zamiast posiadania wielu zmiennych do obsługi tego rodzaju pracy. Operacje w polli selectsą liniowe i powolne z powodu dużej liczby sprawdzeń.

Amir Fo
źródło