Das effiziente Ausführen von Socket-E / A wurde mit Kqueue-, Epoll-, E / A-Abschlussports und dergleichen gelöst. Das Ausführen von asynchronen Datei-E / A ist eine Art Verspätung (abgesehen von der überlappenden E / A-Unterstützung von Windows und der frühen Unterstützung von Solaris für Posix AIO).
Wenn Sie Socket-E / A ausführen möchten, ist es wahrscheinlich besser, einen der oben genannten Mechanismen zu verwenden.
Der Hauptzweck von AIO besteht daher darin, das Problem der asynchronen Festplatten-E / A zu lösen. Dies ist höchstwahrscheinlich der Grund, warum Mac OS X AIO nur für reguläre Dateien und nicht für Sockets unterstützt (da kqueue das sowieso viel besser macht).
Schreibvorgänge werden normalerweise vom Kernel zwischengespeichert und zu einem späteren Zeitpunkt gelöscht. Zum Beispiel, wenn der Lesekopf des Laufwerks zufällig an der Stelle vorbeifährt, an der der Block geschrieben werden soll.
Für Lesevorgänge ist AIO jedoch die einzige Option, wenn der Kernel Ihre Lesevorgänge priorisieren und sortieren soll. Hier ist, warum der Kernal (theoretisch) das besser kann als jede Anwendung auf Benutzerebene:
- Der Kernel sieht alle Festplatten-E / A, nicht nur die Festplattenaufträge Ihrer Anwendungen, und kann sie auf globaler Ebene bestellen
- Der Kernel weiß (möglicherweise), wo sich der Plattenlesekopf befindet, und kann die Leseaufträge, die Sie an ihn weitergeben, in optimaler Reihenfolge auswählen, um den Kopf um die kürzeste Strecke zu bewegen
- Der Kernel kann die native Befehlswarteschlange nutzen , um Ihre Lesevorgänge weiter zu optimieren
- Mit lio_listio () können Sie möglicherweise mehr Lesevorgänge pro Systemaufruf ausführen als mit readv (), insbesondere wenn Ihre Lesevorgänge nicht (logisch) zusammenhängend sind, wodurch ein winziger Teil des Systemaufrufaufwands eingespart wird.
- Ihr Programm ist mit AIO möglicherweise etwas einfacher, da Sie keinen zusätzlichen Thread benötigen, um einen Lese- oder Schreibaufruf zu blockieren.
Das heißt, posix AIO hat eine ziemlich umständliche Oberfläche, zum Beispiel:
- Das einzige effiziente und gut unterstützte Mittel für Ereignisrückrufe sind Signale, was die Verwendung in einer Bibliothek erschwert, da Signalnummern aus dem prozessglobalen Signal-Namespace verwendet werden. Wenn Ihr Betriebssystem keine Echtzeitsignale unterstützt, bedeutet dies auch, dass Sie alle ausstehenden Anforderungen durchlaufen müssen, um herauszufinden, welche tatsächlich abgeschlossen wurden (dies ist beispielsweise bei Mac OS X der Fall, nicht bei Linux). Das Abfangen von Signalen in einer Umgebung mit mehreren Threads führt auch zu einigen kniffligen Einschränkungen. Sie können normalerweise nicht auf das Ereignis im Signalhandler reagieren, müssen jedoch ein Signal auslösen, in eine Pipe schreiben oder signalfd () (unter Linux) verwenden.
- lio_suspend () hat die gleichen Probleme wie select (), es lässt sich nicht sehr gut mit der Anzahl der Jobs skalieren.
- lio_listio () hat, wie implementiert, eine relativ begrenzte Anzahl von Jobs, die Sie übergeben können, und es ist nicht trivial, diese Grenze auf tragbare Weise zu finden. Sie müssen sysconf (_SC_AIO_LISTIO_MAX) aufrufen, was möglicherweise fehlschlägt. In diesem Fall können Sie die AIO_LISTIO_MAX-Definition verwenden, die nicht unbedingt definiert ist, aber dann können Sie 2 verwenden, die als garantiert unterstützt definiert ist.
Für reale Anwendungen mit posix AIO können Sie sich lighttpd (lighty) ansehen, das bei der Einführung der Unterstützung auch eine Leistungsmessung veröffentlicht hat.
Die meisten posix-Plattformen unterstützen derzeit posix AIO (Linux, BSD, Solaris, AIX, tru64). Windows unterstützt es über seine überlappenden Datei-E / A. Ich verstehe, dass nur Solaris, Windows und Linux Async wirklich unterstützen. Datei-E / A bis zum Treiber, während die anderen Betriebssysteme die asynchrone Funktion emulieren. E / A mit Kernel-Threads. Da Linux die Ausnahme darstellt, emuliert die Posix-AIO-Implementierung in glibc asynchrone Operationen mit Threads auf Benutzerebene, während die native asynchrone E / A-Schnittstelle (io_submit () usw.) bis zum Treiber wirklich asynchron ist, vorausgesetzt, der Treiber unterstützt sie .
Ich glaube, es ist unter Betriebssystemen ziemlich üblich, posix AIO für keine fd zu unterstützen, sondern es auf reguläre Dateien zu beschränken.