Die optimale Puffergröße hängt mit einer Reihe von Faktoren zusammen: Dateisystemblockgröße, CPU-Cache-Größe und Cache-Latenz.
Die meisten Dateisysteme sind für die Verwendung von Blockgrößen von 4096 oder 8192 konfiguriert. Wenn Sie Ihre Puffergröße so konfigurieren, dass Sie einige Bytes mehr als den Plattenblock lesen, können die Vorgänge mit dem Dateisystem theoretisch äußerst ineffizient sein (dh wenn Sie dies tun) Wenn Sie Ihren Puffer so konfiguriert haben, dass er jeweils 4100 Byte liest, würde jeder Lesevorgang 2 Blocklesevorgänge durch das Dateisystem erfordern. Wenn sich die Blöcke bereits im Cache befinden, zahlen Sie den Preis für RAM -> L3 / L2-Cache-Latenz. Wenn Sie Pech haben und die Blöcke noch nicht im Cache sind, zahlen Sie auch den Preis für die Disk-> RAM-Latenz.
Aus diesem Grund sehen Sie die meisten Puffer mit einer Größe von 2 und im Allgemeinen größer (oder gleich) der Plattenblockgröße. Dies bedeutet, dass einer Ihrer Stream-Lesevorgänge zu mehreren Lesevorgängen von Festplattenblöcken führen kann. Diese Lesevorgänge verwenden jedoch immer einen vollständigen Block - keine verschwendeten Lesevorgänge.
Dies ist in einem typischen Streaming-Szenario ziemlich ausgeglichen, da der Block, der von der Festplatte gelesen wird, beim nächsten Lesen immer noch im Speicher verbleibt (wir führen hier schließlich sequentielle Lesevorgänge durch) Bezahlen des RAM -> L3 / L2-Cache-Latenzpreises beim nächsten Lesevorgang, nicht jedoch der Festplatten-> RAM-Latenz. In Bezug auf die Größenordnung ist die Disk-> RAM-Latenz so langsam, dass sie jede andere Latenz, mit der Sie möglicherweise zu tun haben, ziemlich überfüllt.
Ich vermute also, dass Sie, wenn Sie einen Test mit verschiedenen Cache-Größen durchgeführt haben (dies nicht selbst getan haben), wahrscheinlich einen großen Einfluss der Cache-Größe bis zur Größe des Dateisystemblocks feststellen werden. Darüber hinaus vermute ich, dass sich die Dinge ziemlich schnell beruhigen würden.
Hier gibt es eine Menge Bedingungen und Ausnahmen - die Komplexität des Systems ist tatsächlich erstaunlich (nur L3 -> L2-Cache-Übertragungen in den Griff zu bekommen, ist erstaunlich komplex und ändert sich mit jedem CPU-Typ).
Dies führt zu der Antwort aus der realen Welt: Wenn Ihre App zu 99% verfügbar ist, stellen Sie die Cache-Größe auf 8192 ein und fahren Sie fort (noch besser, wählen Sie die Kapselung gegenüber der Leistung und verwenden Sie BufferedInputStream, um die Details auszublenden). Wenn Sie zu 1% der Apps gehören, die stark vom Festplattendurchsatz abhängig sind, erstellen Sie Ihre Implementierung so, dass Sie verschiedene Strategien für die Festplatteninteraktion austauschen und die Regler und Wählscheiben bereitstellen können, mit denen Ihre Benutzer testen und optimieren können (oder einige davon entwickeln können) selbstoptimierendes System).
Ja, es hängt wahrscheinlich von verschiedenen Dingen ab - aber ich bezweifle, dass es einen großen Unterschied machen wird. Ich tendiere dazu, mich für 16K oder 32K zu entscheiden, um ein gutes Gleichgewicht zwischen Speichernutzung und Leistung zu finden.
Beachten Sie, dass Sie einen try / finally-Block im Code haben sollten, um sicherzustellen, dass der Stream geschlossen ist, auch wenn eine Ausnahme ausgelöst wird.
quelle
In den meisten Fällen spielt es wirklich keine Rolle. Wählen Sie einfach eine gute Größe wie 4K oder 16K und bleiben Sie dabei. Wenn Sie positiv , dass dies der Engpass in der Anwendung ist, dann sollten Sie beginnen , Profilieren die optimale Puffergröße zu finden. Wenn Sie eine zu kleine Größe auswählen, verschwenden Sie Zeit mit zusätzlichen E / A-Vorgängen und zusätzlichen Funktionsaufrufen. Wenn Sie eine zu große Größe auswählen, werden Sie viele Cache-Fehler sehen, die Sie wirklich verlangsamen. Verwenden Sie keinen Puffer, der größer als Ihre L2-Cache-Größe ist.
quelle
Im Idealfall sollten wir genügend Speicher haben, um die Datei in einem Lesevorgang zu lesen. Dies wäre die beste Leistung, da das System das Dateisystem, die Zuordnungseinheiten und die Festplatte nach Belieben verwalten kann. In der Praxis haben Sie das Glück, die Dateigrößen im Voraus zu kennen. Verwenden Sie einfach die durchschnittliche Dateigröße, die auf 4 KB aufgerundet ist (Standardzuweisungseinheit unter NTFS). Und das Beste: Erstellen Sie einen Benchmark, um mehrere Optionen zu testen.
quelle
Sie können die BufferedStreams / Reader verwenden und dann deren Puffergrößen verwenden.
Ich glaube, die BufferedXStreams verwenden 8192 als Puffergröße, aber wie Ovidiu sagte, sollten Sie wahrscheinlich einen Test für eine ganze Reihe von Optionen durchführen. Es wird wirklich von der Dateisystem- und Festplattenkonfiguration abhängen, welche die besten Größen sind.
quelle
Das Lesen von Dateien mit FileChannel und MappedByteBuffer von Java NIO führt höchstwahrscheinlich zu einer Lösung, die viel schneller ist als jede Lösung mit FileInputStream. Grundsätzlich können Sie große Dateien im Speicher abbilden und direkte Puffer für kleine verwenden.
quelle
In der Quelle von BufferedInputStream finden Sie: private static int DEFAULT_BUFFER_SIZE = 8192;
Es ist also in Ordnung, diesen Standardwert zu verwenden.
Wenn Sie jedoch weitere Informationen finden, erhalten Sie wertvollere Antworten.
Beispielsweise bevorzugt Ihre ADSL möglicherweise einen Puffer von 1454 Byte, was an der Nutzlast von TCP / IP liegt. Für Datenträger können Sie einen Wert verwenden, der der Blockgröße Ihres Datenträgers entspricht.
quelle
Verwenden Sie BufferedInputStreams, wie bereits in anderen Antworten erwähnt.
Danach spielt die Puffergröße wohl keine Rolle mehr. Entweder ist das Programm an E / A gebunden, und eine Vergrößerung der Puffergröße gegenüber dem BIS-Standard hat keinen großen Einfluss auf die Leistung.
Oder das Programm ist in MessageDigest.update () CPU-gebunden, und die meiste Zeit wird nicht im Anwendungscode verbracht, sodass das Optimieren nicht hilft.
(Hmm ... bei mehreren Kernen könnten Threads helfen.)
quelle
1024 ist für eine Vielzahl von Umständen geeignet, obwohl Sie in der Praxis möglicherweise eine bessere Leistung bei einer größeren oder kleineren Puffergröße sehen.
Dies würde von einer Reihe von Faktoren abhängen, einschließlich der Blockgröße des Dateisystems und der CPU-Hardware.
Es ist auch üblich, eine Potenz von 2 für die Puffergröße zu wählen, da die meiste zugrunde liegende Hardware mit Fle-Block- und Cache-Größen strukturiert ist, die eine Potenz von 2 sind. Mit den gepufferten Klassen können Sie die Puffergröße im Konstruktor angeben. Wenn keine angegeben ist, verwenden sie einen Standardwert, der in den meisten JVMs eine Zweierpotenz ist.
Unabhängig davon, welche Puffergröße Sie auswählen, ist die größte Leistungssteigerung der Übergang vom ungepufferten zum gepufferten Dateizugriff. Das Anpassen der Puffergröße kann die Leistung geringfügig verbessern. Wenn Sie jedoch keine extrem kleine oder extrem große Puffergröße verwenden, ist es unwahrscheinlich, dass dies erhebliche Auswirkungen hat.
quelle