W przypadku bardzo małej liczby gniazd (różni się oczywiście w zależności od sprzętu, ale mówimy o czymś, co jest rzędu 10 lub mniej), funkcja select może pokonać epoll w zużyciu pamięci i szybkości działania. Oczywiście przy tak małej liczbie gniazd oba mechanizmy są tak szybkie, że w zdecydowanej większości przypadków nie przejmujesz się tą różnicą.
Jedno wyjaśnienie. Zarówno wybierz, jak i epoll skalują liniowo. Dużą różnicą jest jednak to, że interfejsy API skierowane do przestrzeni użytkownika mają złożoność opartą na różnych rzeczach. Koszt select
połączenia jest mniej więcej równy wartości podanego deskryptora pliku o najwyższym numerze. Jeśli wybierzesz na jednym fd, 100, to jest to mniej więcej dwa razy droższe niż wybranie na jednym fd, 50. Dodanie większej liczby fd poniżej najwyższego nie jest całkiem darmowe, więc jest to trochę bardziej skomplikowane niż to w praktyce, ale to jest dobrym pierwszym przybliżeniem dla większości implementacji.
Koszt epoll jest bliższy liczbie deskryptorów plików, które faktycznie zawierają zdarzenia. Jeśli monitorujesz 200 deskryptorów plików, ale tylko 100 z nich ma zdarzenia, wtedy (z grubsza) płacisz tylko za te 100 aktywnych deskryptorów plików. W tym przypadku epoll ma zwykle jedną ze swoich głównych zalet w stosunku do Select. Jeśli masz tysiąc klientów, którzy są w większości bezczynni, to kiedy używasz select, nadal płacisz za wszystkie tysiąc z nich. Jednak w przypadku epoll wygląda to tak, jakbyś miał tylko kilka - płacisz tylko za te, które są aktywne w danym momencie.
Wszystko to oznacza, że epoll spowoduje mniejsze wykorzystanie procesora w przypadku większości obciążeń. Jeśli chodzi o użycie pamięci, to trochę rzutowanie. select
udaje się przedstawić wszystkie niezbędne informacje w bardzo zwarty sposób (jeden bit na deskryptor pliku). A ograniczenie FD_SETSIZE (zwykle 1024) dotyczące liczby deskryptorów plików, których możesz użyć, select
oznacza, że nigdy nie wydasz więcej niż 128 bajtów na każdy z trzech zestawów fd, których możesz użyćselect
(czytaj, pisz, wyjątek). W porównaniu do tych maksymalnie 384 bajtów, epoll jest czymś w rodzaju świni. Każdy deskryptor pliku jest reprezentowany przez strukturę wielobajtową. Jednak w kategoriach bezwzględnych nadal nie będzie zużywał dużo pamięci. Możesz przedstawić ogromną liczbę deskryptorów plików w kilkudziesięciu kilobajtach (myślę, że około 20k na 1000 deskryptorów plików). Możesz także dorzucić fakt, że musisz wydać wszystkie 384 z tych bajtów, select
jeśli chcesz monitorować tylko jeden deskryptor pliku, ale jego wartość wynosi 1024, podczas gdy w przypadku epoll wydasz tylko 20 bajtów. Mimo to wszystkie te liczby są dość małe, więc nie ma to większego znaczenia.
Jest też inna zaleta epoll, o której być może już wiesz, że nie ogranicza się ona do deskryptorów plików FD_SETSIZE. Możesz go użyć do monitorowania dowolnej liczby deskryptorów plików. A jeśli masz tylko jeden deskryptor pliku, ale jego wartość jest większa niż FD_SETSIZE, epoll też z tym działa, ale select
tak nie jest.
Losowo niedawno odkryłem również jedną drobną wadę epoll
w porównaniu z select
lub poll
. Chociaż żaden z tych trzech interfejsów API nie obsługuje zwykłych plików (tj. Plików w systemie plików), select
i poll
przedstawia ten brak wsparcia jako zgłaszanie takich deskryptorów jako zawsze czytelnych i zawsze zapisywalnych. To sprawia, że nie nadają się do żadnego znaczącego rodzaju nieblokującego wejścia / wyjścia systemu plików, program, który używa select
lub poll
i zdarza się napotkać deskryptor pliku z systemu plików, będzie przynajmniej kontynuował działanie (lub jeśli się nie powiedzie, nie będzie to spowodowane z select
lub poll
), choć być może nie o najlepszej wydajności.
Z drugiej strony epoll
zawiedzie szybko z błędem ( EPERM
najwyraźniej), gdy zostanie wyświetlony monit o monitorowanie takiego deskryptora pliku. Ściśle mówiąc, nie jest to błędne. Po prostu sygnalizuje brak wsparcia w wyraźny sposób. Normalnie biłbym brawa dla jawnych warunków awarii, ale ten jest nieudokumentowany (o ile wiem) i skutkuje całkowicie zepsutą aplikacją, a nie taką, która działa tylko z potencjalnie obniżoną wydajnością.
W praktyce jedyne miejsce, w którym widziałem, to podczas interakcji ze stdio. Użytkownik może przekierować stdin lub stdout z / do normalnego pliku. Podczas gdy wcześniej stdin i stdout byłyby potokiem - obsługiwanym przez epoll w porządku - wtedy staje się normalnym plikiem i epoll głośno kończy się niepowodzeniem, co powoduje uszkodzenie aplikacji.
poll
celu uzyskania kompletności?