Gibt es unter Linux wirklich keine asynchrone Block-E / A?

Stellen Sie sich eine Anwendung vor, die an die CPU gebunden ist, aber auch hohe E / A-Anforderungen hat.

Ich vergleiche Linux-Datei-E / A mit Windows und kann nicht erkennen, wie epoll einem Linux-Programm überhaupt hilft. Der Kernel teilt mir mit, dass der Dateideskriptor "bereit zum Lesen" ist, aber ich muss noch blockieren read () aufrufen, um meine Daten zu erhalten, und wenn ich Megabyte lesen möchte, ist es ziemlich klar, dass dies blockieren wird.

Unter Windows kann ich ein Dateihandle mit OVERLAPPED-Satz erstellen und dann nicht blockierende E / A verwenden. Ich werde benachrichtigt, wenn die E / A abgeschlossen ist, und verwende die Daten aus dieser Abschlussfunktion. Ich muss keine Zeit auf der Anwendungsebene mit dem Warten auf Daten verbringen, was bedeutet, dass ich die Anzahl der Threads genau auf die Anzahl der Kerne abstimmen und eine 100% effiziente CPU-Auslastung erzielen kann.

Wenn ich unter Linux asynchrone E / A-Vorgänge emulieren muss, muss ich dafür eine bestimmte Anzahl von Threads zuweisen. Diese Threads verbringen ein wenig Zeit mit CPU-Vorgängen und viel Zeit mit dem Blockieren von E / A-Vorgängen. Darüber hinaus ist der Nachrichtenaustausch zu / von diesen Threads mit einem Mehraufwand verbunden. Daher werde ich meine CPU-Kerne entweder überbeanspruchen oder unterbeanspruchen.

Ich habe mmap () + madvise () (WILLNEED) als "asynchrone E / A eines armen Mannes" angesehen, aber es kommt immer noch nicht ganz dort an, weil ich keine Benachrichtigung bekomme, wenn es fertig ist - das habe ich zu "erraten" und wenn ich "falsch" errate, werde ich am Ende den Speicherzugriff blockieren und darauf warten, dass Daten von der Festplatte kommen.

Linux scheint in io_submit asynchrone E / A-Vorgänge zu starten, und es scheint auch eine POSIX-AIO-Implementierung für den Benutzerbereich zu geben, aber das ist schon seit einiger Zeit so, und ich kenne niemanden, der für diese Systeme für kritisch bürgt , Hochleistungsanwendungen.

Das Windows-Modell funktioniert ungefähr so:

Setzen Sie eine asynchrone Operation ab.Binden Sie die asynchrone Operation an einen bestimmten E / A-Abschlussport.Warten Sie, bis der Vorgang an diesem Port abgeschlossen istWenn die E / A abgeschlossen ist, wird der Thread, der auf den Port wartet, freigegeben und gibt einen Verweis auf die ausstehende E / A-Operation zurück.

Die Schritte 1/2 werden normalerweise als eine einzelne Sache ausgeführt. Die Schritte 3/4 werden in der Regel mit einem Pool von Arbeitsthreads ausgeführt, die (nicht unbedingt) mit dem Thread identisch sind, der die E / A ausgibt. Dieses Modell ähnelt dem von boost :: asio bereitgestellten Modell, mit der Ausnahme, dass boost :: asio keine asynchronen blockbasierten (Festplatten-) E / A-Vorgänge liefert.

Der Unterschied zu epoll unter Linux besteht darin, dass in Schritt 4 noch keine E / A-Vorgänge stattgefunden haben. Schritt 1 wird nach Schritt 4 gesetzt. Dies ist "rückwärts", wenn Sie genau wissen, was Sie bereits benötigen.

Nachdem ich eine große Anzahl von Embedded-, Desktop- und Server-Betriebssystemen programmiert habe, kann ich sagen, dass dieses Modell der asynchronen E / A für bestimmte Arten von Programmen sehr natürlich ist. Es hat auch einen sehr hohen Durchsatz und einen geringen Overhead. Ich denke, dies ist einer der verbleibenden wirklichen Mängel des Linux-E / A-Modells auf API-Ebene.

Antworten auf die Frage(3)

Ihre Antwort auf die Frage