Asynchrones io in c mit Windows-API: Welche Methode zu verwenden und warum führt mein Code synchron?

8

Ich habe eine C-Anwendung, die viel Ausgabe erzeugt und für die Geschwindigkeit entscheidend ist. Das Programm ist im Grunde genommen eine Schleife über eine große Binärdatei (8-12 GB), die sequentiell gelesen werden muss. In jeder Iteration werden die gelesenen Bytes verarbeitet und die Ausgabe wird erzeugt und in mehrere Dateien geschrieben, aber niemals in mehrere Dateien gleichzeitig. Wenn Sie also an dem Punkt sind, wo die Ausgabe erzeugt wird und es 4 Ausgabedateien gibt, schreiben Sie entweder in die Datei 0 oder 1 oder 2 oder 3. Am Ende der Iteration schreibe ich nun die Ausgabe mit fwrite() und warte darauf die Schreiboperation zum Beenden. Die Gesamtanzahl der Ausgabevorgänge ist groß, bis zu 4 Millionen pro Datei, und die Ausgabegröße der Dateien reicht von 100 MB bis 3,5 GB. Das Programm läuft auf einem Basis-Multicore-Prozessor.

Ich möchte die Ausgabe in einen separaten Thread schreiben und ich weiß, dass dies mit

erledigt werden kann
  1. Asynchrone I / O
  2. Erstellen von Threads
  3. E / A-Abschluss-Ports

Ich habe zwei Arten von Fragen, nämlich konzeptionell und code-spezifisch.

Begriffsfrage

Was wäre der beste Ansatz? Beachten Sie, dass die Anwendung auf Linux portierbar sein sollte. Ich sehe jedoch nicht, dass dies für meine Entscheidung für 1-3 sehr wichtig wäre, da ich einen Wrapper für alles Kernel / API-spezifische schreiben würde. Das wichtigste Kriterium ist für mich die Geschwindigkeit. Ich habe gelesen, dass Option 1 nicht wahrscheinlich die Leistung des Programms erhöht und dass der Kernel in jedem Fall neue Threads für die I / O-Operation erstellt, also warum nicht sofort die Option (2) verwenden, mit dem Vorteil, dass es scheint einfacher zu programmieren (auch weil ich mit Option (1) nicht erfolgreich war, siehe Code-Probleme unten).

Beachten Sie, dass ich Ссылка , aber ich sehe keine Motivation Was zu verwenden, basierend auf der Art der Anwendung. Ich hoffe also, dass jemand mir einen Rat geben könnte, was in meiner Situation am besten wäre. Auch aus dem Buch "Windows System Programming" von Johnson M. Hart weiß ich, dass die Empfehlung hauptsächlich wegen der Einfachheit Threads verwendet. Aber wird es auch am schnellsten sein?

Code Frage

Diese Frage bezieht sich auf die bisherigen Versuche, asynchrone E / A zu arbeiten. Ich verstehe, dass es ein großes Stück Code ist, so dass es nicht so einfach ist, in zu schauen. Auf jeden Fall würde ich jeden Versuch sehr schätzen.

Um die Ausführungszeit zu verkürzen, versuche ich die Ausgabe mittels eines neuen Threads mit WINAPI über CreateFile() mit FILE_FLAGGED_OVERLAP mit einer überlappenden Struktur zu schreiben. Ich habe ein Beispielprogramm erstellt, in dem ich versuche, das zum Laufen zu bringen. Ich stieß jedoch auf 2 Probleme:

  1. Die Datei wird nur im überlappenden Modus geöffnet, wenn ich eine bereits existierende Datei lösche (Ich habe CreateFile in verschiedenen Modi versucht ( CREATE_ALWAYS , CREATE_NEW , OPEN_EXISTING ), aber dies nicht Hilfe).

  2. Nur der erste WriteFile wird asynchron ausgeführt. Der Rest von WriteFile -Befehlen ist synchron. Für dieses Problem habe ich bereits Ссылка konsultiert. Es scheint, dass das Problem, das ich habe, mit der Tatsache zusammenhängt, dass "jede Schreiboperation zu einer Datei, die ihre Länge verlängert, synchron sein wird". Ich habe bereits versucht, dies zu lösen, indem ich die Dateigröße / gültige Datengröße (kommentierte Region im Code) erhöht habe. Aber ich bekomme es immer noch nicht zur Arbeit. Ich bin mir der Tatsache bewusst, dass es möglich sein könnte, dass ich das meiste aus dem asynchronen io heraushole, ich sollte CreateFile mit FILE_FLAG_NO_BUFFERING , aber ich kann das auch nicht zum Laufen bringen.

Bitte beachten Sie, dass das Programm im Ausführungspfad eine Datei von ca. 120mb erstellt. Beachten Sie auch, dass Druckanweisungen "nicht ok" nicht wünschenswert sind, ich würde gerne sehen, dass "Kann im Hintergrund arbeiten" auf meinem Bildschirm erscheinen ... Was läuft hier falsch?

%Vor%

Nützliche Links

Ich weiß, dass dies eine große Frage ist, und ich möchte allen im Voraus danken, die sich die Mühe machen, sie zu lesen und vielleicht sogar zu antworten!

    
Martin 15.12.2010, 14:51
quelle

3 Antworten

2

Sie sollten dies mithilfe der OVERLAPPED-Struktur zum Laufen bringen können.

Sie sind auf dem richtigen Weg: Das System verhindert, dass Sie asynchron schreiben, weil jedes WriteFile die Größe der Datei erweitert. Sie führen jedoch die Dateigrößenerweiterung falsch aus. Wenn Sie SetFileSize aufrufen, wird tatsächlich kein Speicherplatz in der MFT reserviert. Verwenden Sie die SetFileValidData-Funktion. Dies wird Cluster für Ihre Datei zuweisen (beachten Sie, dass sie den Müll enthalten, den die Platte dort hatte) und Sie sollten in der Lage sein, WriteFile und Ihre Berechnung parallel auszuführen.

Ich würde mich von FILE_FLAG_NO_BUFFERING fernhalten. Sie sind auf der Suche nach mehr Leistung mit Parallelität, nehme ich an? Verhindern Sie nicht, dass der Cache seine Aufgabe erfüllt.

    
martona 15.12.2010, 23:04
quelle
1

Eine weitere Option, die Sie nicht berücksichtigt haben, ist eine Speicherabbilddatei. Diese sind unter Windows und Linux verfügbar. Es gibt eine nützliche Boost-Abstraktion, die Sie verwenden könnten.

Mit einer Memory-Mapped-Datei, jeder Thread in Ihrem Prozess seine Ausgabe an die Datei auf seiner eigenen Zeit schreiben konnte, unter der Annahme, dass die Plattengrößen sind bekannt und jeder Thread hat seinen eigenen Ausgabebereich.

Das Betriebssystem wird sich darum kümmern, die gemappten Seiten bei Bedarf auf die Festplatte zu schreiben oder wenn es dazu kommt oder wenn Sie die Datei schließen. Vielleicht, wenn Sie die Datei schließen. Nun, da ich darüber nachdenke, erfordern einige Betriebssysteme, dass Sie msync aufrufen, um dies zu garantieren.

    
Zan Lynx 16.12.2010 00:02
quelle
0

Ich verstehe nicht, warum Sie asynchron schreiben möchten. Dinge parallel zu tun macht sie nicht in allen Fällen schneller. Wenn Sie zwei Dateien gleichzeitig auf dieselbe Festplatte schreiben, wird es fast immer viel schneller. Wenn dies der Fall ist, schreibe sie einfach nacheinander.

Wenn Sie ein ausgefallenes Laufwerk wie SSD oder ein virtuelles RAM-Laufwerk haben, könnte paralleles Schreiben schneller sein. Sie müssen eine Datei in voller Größe erstellen und dann Ihre parallele Magie tun.

Asynchrones Schreiben ist nett, wird aber von jedem OS sowieso gemacht. Der potentielle Gewinn für Sie besteht darin, dass Sie andere Dinge tun können, als wenn Sie auf die Festplatte schreiben, wie zum Beispiel das Anzeigen einer Fortschrittsleiste. Dies ist, wo Multi-Threading Ihnen helfen kann.

Also sollten Sie serielles Schreiben oder paralleles Schreiben auf mehrere Festplatten verwenden.

hth

    
msteiger 15.12.2010 15:56
quelle