Frage

Ich möchte eine Frage stellen, dann Folgen ihm mit meiner eigenen Antwort, aber auch sehen, welche Antworten andere Menschen haben.

Wir haben zwei große Dateien, die wir Lesen möchten, aus zwei separaten threads gleichzeitig.Ein thread nacheinander Lesen, fileA, während der andere thread wird sequenziell Lesen fileB.Es gibt keine sperren oder die Kommunikation zwischen den threads, die beide nacheinander zu Lesen, so schnell wie Sie können, und beide sofort verwerfen der Daten, die Sie Lesen.

Unsere Erfahrung mit diesem setup auf Windows ist sehr schlecht.Die kombinierten Durchsatz der beiden Fäden in der Größenordnung von 2-3 MiB/sec.Das Laufwerk scheint zu sein, verbringen die meiste Zeit mit der Suche rückwärts und vorwärts zwischen den beiden Dateien, vermutlich beim Lesen sehr wenig, nach jedem zu suchen.

Wenn wir deaktivieren eines threads und vorübergehend Blick auf die Leistung eines einzelnen Threads dann bekommen wir viel bessere Bandbreite (~45 MB/Sek. für diese Maschine).So klar die schlechte zwei-thread-performance ist ein Artefakt der OS-Festplatten-scheduler.

Ist es etwas, was wir tun können, um verbessern die gleichzeitige thread gelesen Leistung? Vielleicht mithilfe von verschiedenen APIs oder durch anpassen der OS-Festplatten-scheduler-Parameter in einige Weg.

Einige details:

Die Dateien werden in der Reihenfolge von 2 GiB jeweils an einer Maschine mit 2GB RAM.Für die Zwecke dieser Frage betrachten wir Sie nicht im Cache zwischengespeichert werden und perfekt defragmentiert.Wir haben defrag-tools und neu gestartet, um sicherzustellen, dass dies der Fall ist.

Wir verwenden keine speziellen APIs, diese Dateien zu Lesen.Das Verhalten ist reversibel, über verschiedene Moor-standard-APIs wie Win32 s CreateFile C fopen, C++'s std::ifstream, Java FileInputStream, etc.

Jeder thread dreht sich in eine Schleife zu machen Anrufe auf die read-Funktion.Wir haben variiert die Anzahl der angeforderten bytes aus dem API-jeder iteration von Werten zwischen 1KiB bis zu 128MiB.Unterschiedliche hat dies keine Wirkung hatte, so deutlich die Menge der OS ist körperlich Lesen nach jeder Festplatte suchen, ist nicht diktiert von dieser Nummer.Das ist genau das, was erwartet werden sollte.

Der dramatische Unterschied zwischen einem thread und zwei-thread-Leistung wiederholbar ist über Windows 2000, Windows XP (32-bit und 64-bit), Windows Server 2003 und auch mit und ohne hardware-RAID5.

War es hilfreich?

Lösung

Das problem scheint zu sein, in Windows-I/O-scheduling-Strategie.Nach dem, was ich gefunden hier es gibt viele Möglichkeiten für eine O. S.um den Zeitplan der Festplatte Anforderungen.Während Linux und andere können wählen zwischen verschiedenen Politiken, bevor Vista Windows wurde gesperrt in einer einzigen Richtlinie:eine FIFO-Warteschlange, wo alle Anforderungen, bei denen aufgeteilt in 64-KB-Blöcken.Ich glaube, dass diese Politik ist die Ursache für das problem bei Ihnen Auftritt:der scheduler wird-mix-Anfragen aus den beiden threads, wodurch die kontinuierliche sucht zwischen verschiedenen Bereiche der Festplatte.
Nun, die gute Nachricht ist, dass nach hier und hier, Vista eingeführt, ein intelligenter Festplatten-scheduler, wo Sie können die Priorität Ihrer Anfragen und auch die Zuweisung mindestens badwidth für Ihren Prozess.
Die schlechte Nachricht ist, dass ich keine Möglichkeit gefunden das zu ändern disk-Richtlinie oder Puffer Größe, die in früheren Versionen von Windows.Auch wenn die Anhebung disk-I/O-Priorität des Prozesses erhöhen die Leistung gegen die anderen Prozesse, haben Sie immer noch die Probleme deines threads gegeneinander antreten.
Was ich vorschlagen kann, ist zu ändern Sie Ihre software durch die Einführung eines self-made-disk-access-policy.
Beispielsweise könnten Sie eine Richtlinie verwenden, wie Sie dies in Ihrem thread B (ähnlich Thread):

if THREAD A is reading from disk then wait for THREAD A to stop reading or wait for X ms
Read for X ms (or Y MB)
Stop reading and check status of thread A again  

Sie könnte verwenden Sie Semaphore für den status zu prüfen oder Sie könnte verwenden Sie perfmon-Zähler, um den status der aktuellen disk queue.Die Werte von X und/oder Y könnte auch auto-tuned durch die Prüfung der tatsächlichen Fahrt Preise und langsam zu ändern, und maximiert somit die throughtput, wenn die Anwendung ausgeführt wird, auf verschiedenen Rechnern und/oder O. S.Sie könnte finden, dass die cache -, Speicher-oder RAID-Ebenen, die Sie betreffen, in eine oder andere Weise, aber mit auto-tuning erhalten Sie immer die beste Leistung in jedem Szenario.

Andere Tipps

Ich möchte noch hinzufügen, einige weitere Bemerkungen in meiner Antwort.Alle anderen nicht-Microsoft-Betriebssystemen, die wir getestet haben, nicht leiden unter diesem problem.Linux, FreeBSD und Mac OS X (diese letzten, die auf verschiedenen hardware) alle degradieren viel mehr anmutig in Bezug auf die aggregierte Bandbreite beim verschieben von einem Faden auf zwei.Linux für Beispiel, abgebaut von ~45 MB/s auf ~42 MiB/sec.Diese anderen Betriebssysteme muss gelesen werden größere Abschnitte der Datei zwischen den einzelnen suchen und dafür nicht zu verbringen fast alle Ihre Zeit warten auf der Platte zu suchen.

Unsere Lösung für Windows ist das bestehen der FILE_FLAG_NO_BUFFERING flag CreateFile und große (~16MiB) liest in jeder Aufruf von ReadFile.Das ist nicht optimal für mehrere Gründe:

  • Dateien, die nicht zwischengespeichert werden, wenn Sie Lesen, wie diese, so gibt es keine der Vorteile, die Zwischenspeicherung der Regel gibt.
  • Die Einschränkungen bei der Arbeit mit diesem Kennzeichen sind viel komplizierter als normal Lesen (die Ausrichtung der lese-Puffer Seite Grenzen überschreiten, etc).

(Als Letzte Bemerkung.Tut dies erklären, warum tauschen unter Windows ist es so höllisch?Ie, Windows unfähig ist, zu tun, IO, um mehrere Dateien gleichzeitig mit Effizienz, also beim vertauschen der alle anderen E / a-Operationen sind gezwungen, unverhältnismäßig langsam.)


Bearbeiten Sie, fügen Sie einige weitere details Wird Dekan:

Natürlich in die verschiedenen hardware-Konfigurationen die rohen zahlen geändert haben (manchmal erheblich).Das problem ist jedoch die konsequente Verschlechterung der Leistung, dass nur Windows leidet, wenn Sie sich von einem Faden auf zwei.Hier ist eine Zusammenfassung der Maschinen getestet:

  • Mehrere Dell-workstations (Intel Xeon) in verschiedenen Altersgruppen unter Windows 2000, Windows XP (32-bit), Windows XP (64-bit) mit single-drive.
  • A Dell 1U server (Intel Xeon) unter Windows Server 2003 (64-bit mit RAID-1+0.
  • Eine HP-workstation (AMD Opteron) mit Windows XP (64-bit) und Windows Server 2003 -, und hardware-RAID-5.
  • My home no-name-PC (AMD Athlon 64) unter Windows XP (32-bit), FreeBSD (64-bit) und Linux (64-bit) mit single-drive.
  • Mein Zuhause MacBook (Intel Core1) unter Mac OS X -, Einzel-SATA-Laufwerk.
  • Mein Zuhause Koolu PC mit Linux.Stark untermotorisiert im Vergleich zu den anderen Systemen, aber ich habe gezeigt, dass auch diese Maschine an Leistung übertreffen können einen Windows-server mit RAID5 bei der multi-Thread-disk liest.

Die CPU-Auslastung auf allen diesen Systemen war sehr niedrig, während die tests und anti-virus deaktiviert war.

Ich vergaß zu erwähnen, bevor, aber wir haben auch versucht das normale Win32 CreateFile API-mit der FILE_FLAG_SEQUENTIAL_SCAN - flag gesetzt ist.Dieses flag hat das problem nicht behoben.

Es scheint ein wenig seltsam, dass Sie keinen Unterschied auf ziemlich Breite Palette von windows-Versionen und nichts zwischen einen einzigen Antriebs-und hardware-raid-5.

Es ist nur "Bauchgefühl", aber das macht mich zweifelhaft, dass dies wirklich eine einfache Suche problem.Andere als die OS X-und Raid5 -, war all das versucht auf der gleichen Maschine - haben Sie versucht, eine andere Maschine?Ist Ihre CPU-Auslastung im Grunde genommen bei null bei diesem test?

Was ist die kürzeste app, die Sie schreiben kann, das veranschaulicht dieses problem?- Ich wäre daran interessiert zu versuchen es hier.

Ich würde eine Art von in-memory-thread-safe lock.Jeder thread warten konnte auf das Schloss, bis es frei war.Wenn Sie die Sperre frei wird, die Sperre, Lesen Sie die Datei für eine bestimmte Zeit oder eine bestimmte Menge an Daten, dann lassen Sie die Sperre für alle anderen wartenden threads.

Verwenden Sie IOCompletionPorts unter Windows?Windows via C++ hat eine in die Tiefe gehende Kapitel zu diesem Thema und wie der Zufall es will, es ist auch auf MSDN verfügbar.

Paul sah das update.Sehr interessant.

Es wäre interessant zu versuchen, es auf Vista oder Win2008, wie die Menschen zu sein scheinen reporting einige erhebliche I/O-Verbesserungen, auf diese in einigen Fällen.

Mein einziger Vorschlag über eine andere API zu versuchen memory mapping-Dateien - haben Sie ausprobiert?Leider bei 2 GB pro Datei, du bist nicht in der Lage sein, mehrere anzeigen ganzen Dateien auf einem 32-bit-Maschine, was bedeutet, dass dies nicht ganz so trivial, wie es sein könnte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top