Frage

Ich habe eine Methode, die eine Message (ein Hash) aus einer Datei erstellt, und ich brauche, dies zu tun, um eine Menge von Dateien (> = 100.000). Wie groß soll ich mache die Puffer aus den Dateien zu lesen, die Leistung zu maximieren?

Die meisten jeder ist vertraut mit dem Basiscode (die ich hier nur für den Fall wiederholen werde):

MessageDigest md = MessageDigest.getInstance( "SHA" );
FileInputStream ios = new FileInputStream( "myfile.bmp" );
byte[] buffer = new byte[4 * 1024]; // what should this value be?
int read = 0;
while( ( read = ios.read( buffer ) ) > 0 )
    md.update( buffer, 0, read );
ios.close();
md.digest();

Was ist die ideale Größe des Puffers den Durchsatz zu maximieren? Ich weiß, dass dieses System abhängig ist, und ich bin mir ziemlich sicher, dass sein Betriebssystem, Dateisystem, und HDD abhängig, und dort möglicherweise andere Hardware / Software in der Mischung.

(Ich möchte darauf hinweisen, dass ich auf Java etwas neu bin, so kann dies nur einig Java-API-Aufruf sein, ich weiß nicht, über.)

Edit: Ich weiß nicht, vor der Zeit auf die Arten von Systemen werden diese verwendet werden, also kann ich nicht viel übernehmen. (Ich bin mit Java aus diesem Grunde.)

Edit: Der obige Code wird Dinge wie try..catch fehlt, um den Beitrag kleiner

War es hilfreich?

Lösung

Die optimale Puffergröße auf eine Reihe von Dingen in Beziehung steht. Dateisystem-Blockgröße, CPU-Cache-Größe und Cache-Latenz

Die meisten Dateisysteme konfiguriert sind Blockgrößen von 4096 oder 8192. In der Theorie zu verwenden, wenn Sie Ihre Puffergröße konfigurieren, so dass Sie ein paar Bytes mehr als die Plattenblock lesen, können die Operationen mit dem Dateisystem extrem ineffizient sein ( dh, wenn Sie Ihren Puffer konfigurieren 4100 Bytes zu einer Zeit, zu lesen, würde erfordern, jede Lese 2 Block liest durch das Dateisystem). Wenn die Blöcke bereits im Cache sind, dann wickeln Sie den Preis für RAM zahlen bis -> L3 / L2-Cache-Latenz. Wenn Sie noch Pech und die Blöcke sind nicht im Cache sind, zahlen die Sie den Preis des Disk-> RAM Latenz als auch.

Dies ist, warum Sie die meisten Puffer dimensionierten als eine Potenz von 2, und in der Regel größer als (oder gleich) die Plattenblockgröße zu sehen. Das bedeutet, dass ein Ihren Strom in könnte dazu führen, liest mehrere Plattenblock liest - aber die liest, wird immer einen vollen Block verwenden - Nr. Verschwendet liest

Nun wird dieser Versatz ein gutes Stück in einem typischen Streaming-Szenario, da der Block, der von der Platte gelesen wird, ist immer noch in Erinnerung sein, wenn Sie die nächsten Lese-Treffer (wir tun sequenziell hier liest, nachdem alle) - so Du aufzuwickeln den RAM zahlen -> L3 / L2-Cache-Latenz Preis auf der nächsten Lese, aber nicht die Disk-> RAM Latenz. In Bezug auf die Größenordnung ist Disk-> RAM Latenz so langsam, dass es ziemlich viel Sümpfe andere Latenz Sie mit zu tun haben könnten.

So vermute ich, dass, wenn Sie einen Test mit verschiedenen Cache-Größen lief (haben diese selbst nicht getan), werden Sie wahrscheinlich einen großen Einfluss von Cache-Größe bis zu der Größe des Dateisystems Block finden. Darüber, vermute ich, dass die Dinge ziemlich schnell ausgleichen würden.

Es gibt eine ton von Bedingungen und Ausnahmen hier - die Komplexität des Systems sind eigentlich ganz Staffelung (nur im Griff L3 bekommen -> L2-Cache Transfers ist Geist bogglingly komplex, und es ändert sich mit jeder CPU-Typ).

Dies führt zu der ‚realen Welt‘ Antwort: Wenn Ihre App wie 99% ist da draußen, die Cache-Größe auf 8192 festgelegt und bewegt auf (noch besser, wählt Kapselung über Leistung und verwenden BufferedInputStream die Details zu verbergen). Wenn Sie in dem 1% der Anwendungen, die auf Plattendurchsatz stark abhängig sind, Handwerk Ihre Implementierung, so dass Sie verschiedene Platteninteraktionsstrategien auslagern können, und bieten die Knöpfe und Regler Ihren Benutzer zu ermöglichen, zu testen und zu optimieren (oder kommen mit einigen Selbstoptimierungssystem).

Andere Tipps

Ja, es ist wahrscheinlich abhängig von verschiedenen Dingen - aber ich bezweifle es wird sehr viel Unterschied machen. Ich neige dazu, für 16K oder 32K als eine gute Balance zwischen Speichernutzung und Performance.

entscheiden

Beachten Sie, dass ein try / finally-Block im Code geschlossen, um sicherzustellen, wird der Strom auch haben sollten, wenn eine Ausnahme ausgelöst wird.

In den meisten Fällen ist es wirklich keine Rolle, dass viel. Wählen Sie einfach eine gute Größe wie 4K oder 16K und bleiben Sie dabei. Wenn Sie positive , dass dies der Engpass in der Anwendung, dann sollten Sie Profilierungs beginnen die optimale Puffergröße zu finden. Wenn Sie eine Größe wählen, die zu klein ist, werden Sie Zeit zu tun zusätzliche I / O-Operationen und zusätzliche Funktionsaufrufe verschwenden. Wenn Sie eine Größe wählen, die zu groß ist, beginnen Sie eine Menge von Cache-Misses zu sehen, die wirklich Sie verlangsamen. Verwenden Sie keinen Puffer größer als Ihre L2-Cache-Größe verwendet werden.

Im Idealfall sollten wir genügend Speicher haben Sie die Datei in einem Lesevorgang zu lesen. Das wäre die beste Performance, weil wir das System verwalten File System, Zuordnungseinheiten und HDD nach Belieben lassen. In der Praxis sind Sie glücklich, die Dateigrößen im Voraus zu wissen, benutzen Sie einfach die durchschnittliche Dateigröße auf 4 KB (Standard-Zuordnungseinheit auf NTFS) aufzurunden. Und das Beste ist: Erstellen Sie eine Benchmark mehrere Optionen zu testen.

Sie könnten die BufferedStreams / Leser verwenden und dann ihre Puffergrößen verwendet werden.

Ich glaube, die BufferedXStreams 8192 als die Puffergröße verwenden, aber wie Ovidiu sagte, sollten Sie vielleicht einen Test auf eine ganze Reihe von Optionen laufen. Es ist wirklich auf dem Dateisystem und Plattenkonfigurationen gehen hängen, was die besten Größen sind.

Lesen von Dateien mit Hilfe von Java NIO des Filechannel und MappedByteBuffer höchstwahrscheinlich zu einer Lösung, die viel schneller als jede Lösung sein wird, Fileinputstream beteiligt sind. Grundsätzlich Speicher-Karte, große Dateien und direkte Puffer für kleine verwenden.

In BufferedInputStream der Quelle finden Sie: private static int DEFAULT_BUFFER_SIZE = 8192;
So ist es okey für Sie, dass Standardwert verwenden.
Aber wenn Sie einige weitere Informationen herauszufinden, werden Sie mehr wertvolle Antworten.
Zum Beispiel Ihre adsl preffer vielleicht einen Puffer von 1454 Byte, das ist, weil TCP / IP-Nutzlast. Für Laufwerke, können Sie einen Wert verwenden, der Ihre Festplatte des Blockgröße entsprechen.

Wie bereits in anderen Antworten erwähnt, verwendet BufferedInputStreams.

Danach, ich denke, die Puffergröße ist nicht wirklich wichtig. Entweder das Programm I / O Bindung und wachsende Puffergröße über BIS Standard wird keine großen Auswirkungen auf die Leistung machen.

oder das Programm CPU ist im Inneren des MessageDigest.update () gebunden ist, und meiste Zeit nicht im Anwendungscode ausgegeben, so zwicken es wird nicht helfen.

(Hmm ... mit mehreren Kernen, Fäden helfen könnten.)

1024 ist geeignet für eine Vielzahl von Umständen, obwohl in der Praxis können Sie eine bessere Leistung mit einer größeren oder kleineren Puffergröße sehen.

Dies würde zu einer Reihe von Faktoren ab, einschließlich der Dateisystemblock Größe und CPU-Hardware.

Es ist auch üblich, eine Potenz von 2 für die Puffergröße zu wählen, da die meisten zugrunde liegenden Hardware ist mit fle Block und Cache-Größen strukturiert, dass eine Potenz von 2. Die Buffered sind Klassen können Sie die Puffergröße im Konstruktor angeben. Wenn keine vorhanden ist, sie verwenden, um einen Standardwert, der eine Potenz von 2 in den meisten JVMs ist.

Unabhängig davon, welche Puffergröße wählen Sie erhöhen die größte Leistung, die Sie wird sieht aus ungepufferten zu gepufferten Dateizugriff zu bewegen. Einstellen der Puffergröße kann leicht verbessern die Leistung, aber wenn man eine extrem kleine verwenden oder extrem große Puffergröße, ist es unwahrscheinlich, dass eine signifcant Auswirkungen haben.

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