Mehrere gleichzeitige Writer (kein Reader) in einer einzigen Datei. Ist es möglich, in .NET performant zu arbeiten?

8

Ich entwickle einen Multisegment-Datei-Downloader. Um diese Aufgabe zu erledigen, erstelle ich zur Zeit so viele temporäre Dateien auf der Festplatte wie Segmente, die ich habe (sie sind während des Herunterladens der Dateien in der Anzahl fixiert). Am Ende erstelle ich einfach eine neue Datei f und kopiere den Inhalt aller Segmente auf f .

Ich habe mich gefragt, ob es keinen besseren Weg gibt, dies zu erreichen. Meine Idealisierung besteht darin, zunächst f in voller Größe zu erstellen und dann die verschiedenen Threads direkt auf ihren Teil zu schreiben. Es muss keine Interaktion zwischen ihnen geben. Wir können davon ausgehen, dass jeder von ihnen an seinem eigenen Startpunkt in der Datei startet und dann Informationen nur sequenziell in die Datei füllt, bis die Aufgabe beendet ist.

Ich habe von Memory-Mapped-Dateien gehört ( Ссылка ) und ich frage mich, ob sie die Lösung für mein Problem sind oder nicht.

Danke

    
devoured elysium 02.01.2014, 05:15
quelle

3 Antworten

1

Die Verwendung der speicherprogrammierten API ist absolut machbar und wird wahrscheinlich recht gut funktionieren - aus diesem Grund würden einige Tests empfohlen.

Wenn Sie nach einer möglichen alternativen Implementierung suchen möchten, habe ich den folgenden Vorschlag.

  • Erstellen Sie eine statische Stack-Datenstruktur, in der die Download-Threads jedes Dateisegment nach dem Herunterladen pushen können.

  • Lassen Sie einen separaten Thread nach Push-Benachrichtigungen auf dem Stapel lauschen. Öffnen Sie die Stack-Dateisegmente und speichern Sie jedes Segment einzeln in der Zieldatei.

Indem Sie dem obigen Muster folgen, haben Sie den Download von Dateisegmenten und das Speichern in eine normale Datei unterteilt, indem Sie einen Stapelcontainer dazwischen legen.

Abhängig von der Implementierung der Stapelverarbeitung können Sie dies mit sehr wenig Thread-Locking implementieren, wodurch die Leistung maximiert wird.

Das Beste daran ist, dass Sie 100% Kontrolle darüber haben, was vor sich geht, und eine Lösung, die portabler ist (falls das jemals ein Problem sein sollte).

Das Stack-Entkopplungsmuster, das Sie tun, kann auch ziemlich allgemein implementiert werden und möglicherweise sogar in der Zukunft wiederverwendet werden.

Die Implementierung ist nicht so komplex und wahrscheinlich auf Augenhöhe mit der Implementierung, die rund um die Memory-Map-API durchgeführt werden muss.

Viel Spaß ...

/ Anders

    
ahybertz 02.01.2014 12:25
quelle
1

Die bisher geposteten Antworten beziehen sich natürlich auf Ihre Frage, aber Sie sollten auch die Tatsache in Betracht ziehen, dass Multithreading-E / A-Schreibvorgänge höchstwahrscheinlich KEINE Leistungsgewinne bringen.

Der Grund für Multi-Threading-Downloads ist offensichtlich und hat dramatische Ergebnisse. Wenn Sie versuchen, die Dateien zu kombinieren, denken Sie daran, dass mehrere Threads einen mechanischen Kopf auf herkömmlichen Festplatten manipulieren. Im Falle von SSDs können Sie eine bessere Leistung erzielen.

Wenn Sie einen einzelnen Thread verwenden, überschreiten Sie die Schreibkapazität der Festplatte auf SEQUENTIELLE Weise. Das ist definitionsgemäß die schnellste Möglichkeit, auf Konventionsdisketten zu schreiben.

Wenn Sie etwas anderes glauben, würde mich interessieren, warum. Ich konzentriere mich lieber auf die Schreibleistung eines einzelnen Threads, indem ich mit Puffergrößen usw herumspiele.

    
Raheel Khan 02.01.2014 15:20
quelle
1

Ja, es ist möglich, aber die einzige Vorsichtsmaßnahme, die Sie haben müssen, ist zu kontrollieren, dass keine zwei Threads am selben Ort der Datei schreiben, ansonsten wird der Dateiinhalt falsch sein.

%Vor%

Nach jedem Write haben wir writeStream.Flush(); verwendet, damit die gepufferten Daten in die Datei geschrieben werden, aber Sie können sie entsprechend Ihren Anforderungen ändern.

Da Sie bereits Code haben, der die Dateisegmente parallel herunterlädt. Die einzige Änderung, die Sie vornehmen müssen, besteht darin, den Dateistream wie oben beschrieben zu öffnen, und statt mehrere Segmente lokal zu erstellen, öffnen Sie einfach den Stream für eine einzelne Datei.

Das startPositionOfSegments ist sehr wichtig und berechnet es perfekt, so dass keine zwei Segmente die gewünschten heruntergeladenen Bytes an den gleichen Ort in der Datei überschreiben, ansonsten wird es ein falsches Ergebnis liefern.

Das obige Verfahren funktioniert perfekt an unserem Ende, aber das kann ein Problem sein, wenn Ihre Segmentgröße zu klein ist (Wir haben es auch gesehen, aber nach der Vergrößerung der Segmente wurde es behoben). Wenn Sie auf eine Ausnahme treffen, können Sie nur den Write -Teil synchronisieren.

    
dbw 02.01.2014 15:11
quelle

Tags und Links