Für eine sehr kleine Anzahl von Sockeln (hängt natürlich von Ihrer Hardware ab, aber wir reden über etwas in der Größenordnung von 10 oder weniger), wählen Sie epoll in Speicherauslastung und Laufzeitgeschwindigkeit. Natürlich sind bei so wenigen Sockeln beide Mechanismen so schnell, dass Sie sich in den allermeisten Fällen nicht wirklich um diesen Unterschied kümmern.
Eine Klarstellung, obwohl. Sowohl select als auch epoll skalieren linear. Ein großer Unterschied besteht jedoch darin, dass die Benutzeroberflächen-APIs Komplexitäten haben, die auf verschiedenen Dingen basieren. Die Kosten eines select
Aufrufs gehen ungefähr mit dem Wert des Dateideskriptors mit der höchsten Nummer einher, den Sie übergeben. Wenn Sie auf einem einzigen fd, 100 wählen, dann ist das ungefähr doppelt so teuer wie die Auswahl auf einem einzigen fd, 50. Das Hinzufügen von mehr fds unterhalb des höchsten ist nicht ganz kostenlos, also ist es etwas komplizierter als das in der Praxis, aber das ist eine gute erste Annäherung für die meisten Implementierungen.
Die Kosten von epoll liegen näher an der Anzahl der Dateideskriptoren, die tatsächlich Ereignisse auf ihnen haben. Wenn Sie 200 Dateideskriptoren überwachen, aber nur 100 davon über Ereignisse verfügen, zahlen Sie (grob gesagt) nur für diese 100 aktiven Dateideskriptoren. Hier bietet epoll einen seiner wichtigsten Vorteile gegenüber der Auswahl. Wenn Sie tausende Kunden haben, die meist untätig sind, dann zahlen Sie, wenn Sie select verwenden, immer noch für alle tausend. Mit epoll haben Sie jedoch nur ein paar - Sie zahlen nur für diejenigen, die zu einem bestimmten Zeitpunkt aktiv sind.
All dies bedeutet, dass epoll bei den meisten Workloads zu weniger CPU-Auslastung führt. Was die Speicherauslastung betrifft, ist es ein bisschen ein Toss Up. select
schafft es, alle notwendigen Informationen in einer sehr kompakten Art und Weise darzustellen (ein Bit pro Dateideskriptor). Und die FD_SETSIZE (typischerweise 1024) Beschränkung, wie viele Dateideskriptoren Sie mit select
verwenden können, bedeutet, dass Sie nie mehr als 128 Bytes für jeden der drei fd-Sätze ausgeben, die Sie mit select
(lesen, schreiben, Ausnahme) verwenden können. Verglichen mit diesen 384 Bytes ist epoll eine Art Schwein. Jeder Dateideskriptor wird durch eine Multi-Byte-Struktur dargestellt. In absoluten Zahlen wird es jedoch immer noch nicht viel Speicher verbrauchen. Sie können eine große Anzahl von Dateideskriptoren in ein paar Dutzend Kilobyte darstellen (ungefähr 20k pro 1000 Dateideskriptoren, denke ich). Und Sie können auch die Tatsache einwerfen, dass Sie alle 384 dieser Bytes mit select
ausgeben müssen, wenn Sie nur einen Dateideskriptor überwachen möchten, aber sein Wert ist zufällig 1024, während Sie mit epoll nur 20 Bytes ausgeben würden. Trotzdem sind all diese Zahlen ziemlich klein, so dass es keinen großen Unterschied macht.
Und es gibt noch diesen anderen Vorteil von epoll, von dem Sie vielleicht schon wissen, dass es nicht auf FD_SETSIZE Dateideskriptoren beschränkt ist. Sie können damit so viele Dateideskriptoren überwachen, wie Sie haben. Und wenn Sie nur einen Dateideskriptor haben, dessen Wert jedoch größer als FD_SETSIZE ist, funktioniert epoll auch, aber select
nicht.
Zufällig habe ich vor kurzem einen kleinen Nachteil zu epoll
im Vergleich zu select
oder poll
entdeckt.Während keine dieser drei APIs normale Dateien (dh Dateien in einem Dateisystem) unterstützt, stellen select
und poll
diesen Mangel an Unterstützung dar, da solche Deskriptoren immer lesbar und immer schreibbar sind. Dies macht sie ungeeignet für jede sinnvolle Art von blockierungsfreiem Dateisystem-I/O, ein Programm, das select
oder poll
verwendet und zufälligerweise einen Dateideskriptor aus dem Dateisystem findet, wird zumindest weiter funktionieren (oder wenn es fehlschlägt, wird es nicht funktionieren sei wegen select
oder poll
), wenn auch vielleicht nicht mit der besten Leistung.
Auf der anderen Seite wird epoll
schnell mit einem Fehler (EPERM
, anscheinend) fehlschlagen, wenn aufgefordert, einen solchen Dateideskriptor zu überwachen. Streng genommen ist das kaum inkorrekt. Es signalisiert lediglich seinen Mangel an Unterstützung auf explizite Weise. Normalerweise würde ich expliziten Fehlerbedingungen applaudieren, aber diese ist undokumentiert (soweit ich das beurteilen kann) und führt zu einer völlig kaputten Anwendung, und nicht zu einer, die lediglich mit einer möglicherweise verschlechterten Leistung arbeitet.
In der Praxis ist der einzige Ort, wo ich diese kommen gesehen habe, ist, wenn sie mit stdio interagieren. Ein Benutzer kann stdin oder stdout von/zu einer normalen Datei umleiten. Während vorher stdin und stdout eine Pipe waren - unterstützt von epoll - ist es eine normale Datei und epoll versagt laut und bricht die Anwendung.
Sehr nette Antwort. Betrachten Sie explizit das Verhalten von 'Poll' aus Gründen der Vollständigkeit? – quark
Meine zwei Cent auf das Verhalten des Lesens von normalen Dateien: Ich bevorzuge im Allgemeinen direkten Ausfall zu Leistungseinbußen. Der Grund ist, dass es viel wahrscheinlicher ist, während der Entwicklung entdeckt zu werden, und somit richtig herumzuarbeiten (sagen wir, indem wir eine alternative Methode haben, die E/A für tatsächliche Dateien zu machen). YMMV natürlich: Es kann keine merkliche Verlangsamung geben, in welchem Fall der Ausfall nicht besser ist. Aber eine dramatische Verlangsamung, die nur in speziellen Fällen auftritt, kann während der Entwicklung sehr schwer zu erfassen sein, so dass sie als echte Zeitbombe zurückbleibt. – quark
Ich muss deine Bearbeitung vollständig lesen. In gewissem Sinne stimme ich zu, dass es wahrscheinlich nicht richtig für epoll ist, seine Vorgänger nicht nachzuahmen, aber dann kann ich mir den Entwickler vorstellen, der den EPERM-Fehler implementiert hat: "Nur weil es immer kaputt war, macht es nicht richtig, meinen zu brechen Gut." Und noch ein weiteres Gegenargument, ich bin ein defensiver Programmierer, alles nach 1 + 1 ist suspekt und ich code so, dass ich graziöse Fehler zulasse. Wenn der Kernel einen unerwarteten Fehler hat, ist das nicht nett oder rücksichtsvoll. – David