Frage

Ich versuche, herauszufinden, ob es einen Unterschied in der Leistung (oder Vorteile), wenn wir nio FileChannel im Vergleich zu normalen FileInputStream/FileOuputStream verwenden, um Dateien zu lesen und schreiben, um Dateisystem. Ich beobachtete, dass auf meiner Maschine beide auf dem gleichen Niveau durchführen, auch oft FileChannel Weg ist langsamer. Kann ich bitte weitere Details Vergleich dieser beiden Methoden kennen. Hier ist der Code, den ich verwendet, die Datei, die, mit denen ich zu testen um 350MB ist. Ist es eine gute Option NIO basierte Klassen für Datei zu verwenden, I / O, wenn ich suche nicht nach dem Zufallsprinzip Zugriff oder andere solche erweiterten Funktionen?

package trialjavaprograms;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class JavaNIOTest {
    public static void main(String[] args) throws Exception {
        useNormalIO();
        useFileChannel();
    }

    private static void useNormalIO() throws Exception {
        File file = new File("/home/developer/test.iso");
        File oFile = new File("/home/developer/test2");

        long time1 = System.currentTimeMillis();
        InputStream is = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(oFile);
        byte[] buf = new byte[64 * 1024];
        int len = 0;
        while((len = is.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        fos.flush();
        fos.close();
        is.close();
        long time2 = System.currentTimeMillis();
        System.out.println("Time taken: "+(time2-time1)+" ms");
    }

    private static void useFileChannel() throws Exception {
        File file = new File("/home/developer/test.iso");
        File oFile = new File("/home/developer/test2");

        long time1 = System.currentTimeMillis();
        FileInputStream is = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(oFile);
        FileChannel f = is.getChannel();
        FileChannel f2 = fos.getChannel();

        ByteBuffer buf = ByteBuffer.allocateDirect(64 * 1024);
        long len = 0;
        while((len = f.read(buf)) != -1) {
            buf.flip();
            f2.write(buf);
            buf.clear();
        }

        f2.close();
        f.close();

        long time2 = System.currentTimeMillis();
        System.out.println("Time taken: "+(time2-time1)+" ms");
    }
}
War es hilfreich?

Lösung

Meine Erfahrung mit größeren Dateigrößen wurde, dass java.nio schneller als java.io ist. Solide schneller. Wie im> 250% -Bereich. Das heißt, ich offensichtliche Engpässe beseitigen bin, die ich Ihre Mikro-Benchmark könnte darauf hindeuten, leiden. Mögliche Bereiche für die Untersuchung:

Die Puffergröße. Der Algorithmus Sie im Grunde genommen haben, ist

  • Kopie von der Festplatte zu puffern
  • Kopie von dem Puffer auf der Festplatte

Meine eigene Erfahrung ist, dass diese Puffergröße reif für Tuning. Ich habe einen Teil meiner Bewerbung, 256 KB für die andere auf 4 KB abgerechnet. Ich vermute, dass der Code mit einem so großen Puffer leidet. Führen Sie einige Benchmarks mit Puffern von 1 KB, 2 KB, 4 KB, 8 KB, 16 KB, 32 KB und 64 KB zu beweisen, dass es an sich selbst.

Sie keine Java-Benchmarks durchführen, die auf der gleichen Festplatte lesen und schreiben.

Wenn Sie das tun, dann sind das Benchmarking Sie wirklich die Platte, und nicht Java. Ich würde auch vorschlagen, dass, wenn Ihre CPU nicht besetzt ist, dann sind Sie wahrscheinlich ein anderes Engpass auftritt.

Verwenden Sie keinen Puffer verwenden, wenn Sie nicht brauchen.

Warum in den Speicher kopieren, wenn Ihr Ziel eine andere Festplatte oder eine NIC ist? Bei größeren Dateien, incured die Latenz ist nicht trivial.

Wie andere gesagt haben, verwenden FileChannel.transferTo() oder FileChannel.transferFrom(). Der entscheidende Vorteil dabei ist, dass der JVM des Zugriff auf DMA-O verwendet ( Direct Memory Access ), wenn vorhanden. (Dies ist abhängig von der Implementierung, aber die moderne Sun und IBM-Versionen auf Allzweck-CPUs sind gut zu gehen.) Was passiert ist, die Daten gehen direkt auf / von der Platte, auf den Bus, und dann an das Ziel ... jede Schaltung durch RAM oder die CPU zu umgehen.

Der Web-App ich meine Tage und Nacht arbeiten verbrachte sehr IO schwer. Ich habe Mikro-Benchmarks durchgeführt und die reale Welt Benchmarks zu. Und die Ergebnisse sind auf meinem Blog, haben Sie einen Blick-See:

Die Nutzung von Produktionsdaten und Umgebungen

Micro-Benchmarks sind anfällig für Verzerrungen. Wenn Sie können, sich die Mühe machen, um Daten zu sammeln aus genau das, was Sie tun möchten, mit der Last, die Sie erwarten, auf der Hardware, die Sie erwarten.

Mein Benchmarks ist solide und zuverlässig, da sie Platz auf einem Produktionssystem haben, ein bulliges System, ein System unter Last, versammeln sich in Protokollen. nicht mein Notebook 7200 RPM 2.5" SATA-Laufwerk, während ich beobachtete, wie intensiv die JVM meine Festplatte arbeiten.

Was laufen Sie? Es ist wichtig.

Andere Tipps

Wenn das, was Sie vergleichen wollen Leistung von Kopieren von Dateien ist, dann für den Kanal-Test Sie sollten dies tun, statt:

final FileInputStream inputStream = new FileInputStream(src);
final FileOutputStream outputStream = new FileOutputStream(dest);
final FileChannel inChannel = inputStream.getChannel();
final FileChannel outChannel = outputStream.getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
inChannel.close();
outChannel.close();
inputStream.close();
outputStream.close();

Dies wird nicht langsamer als sich von einem Kanal zum anderen zu puffern, und wird möglicherweise massiv schneller sein. Nach dem Javadocs:

  

Viele Betriebssysteme können Bytes direkt aus dem Dateisystem-Cachespeicher auf den Zielkanal übertragen, ohne sie tatsächlich zu kopieren.

Basierend auf meinen Tests (Win7 64bit, 6 GB RAM, Java6), ist NIO transferFrom schnell nur mit kleinen Dateien und wird auf größere Dateien sehr langsam. NIO Datenpuffer Flip trifft immer Standard-IO.

  • Kopieren 1000x2MB

    1. NIO (transferFrom) ~ 2300ms
    2. NIO (direkter datababuffer 5000B Flip) ~ 3500ms
    3. Standard IO (Puffer 5000B) ~ 6000ms
  • Kopieren 100x20mb

    1. NIO (direkter datababuffer 5000B Flip) ~ 4000ms
    2. NIO (transferFrom) ~ 5000 ms
    3. Standard IO (Puffer 5000B) ~ 6500ms
  • Kopieren 1x1000mb

    1. NIO (direkter datababuffer 5000B Flip) ~ 4500S
    2. Standard IO (Puffer 5000B) ~ 7000ms
    3. NIO (transferFrom) ~ 8000ms

Die transferTo () -Methode auf Chunks einer Datei arbeitet; wurde nicht als High-Level-Dateikopiermethode bestimmt: Wie eine große Datei in Windows XP kopieren?

den "Nützlichkeit" Teil der Frage zu beantworten:

Eine eher dezente gotcha FileChannel über FileOutputStream der Verwendung ist, dass jede seiner Sperroperationen (zB read() oder write()) von einem Thread durchführen, die in unterbrochenen Zustand der Kanal verursachen wird abrupt mit java.nio.channels.ClosedByInterruptException .

Nun könnte dies eine gute Sache sein, wenn alles, was die FileChannel für ist Teil der Threads Hauptfunktion verwendet wurde, und das Design hat dies berücksichtigen.

Aber es könnte auch nervtötende sein, wenn durch eine Hilfs Funktion wie eine Logging-Funktion verwendet. Zum Beispiel können Sie Ihre Log-Ausgabe plötzlich geschlossen, wenn die Logging-Funktion geschieht genannt werden durch einen Faden finden, der auch unterbrochen wird.

Es ist bedauerlich, diese so subtil ist, weil nicht für diese Bilanzierung zu Fehlern führen kann, die Integrität beeinflussen schreiben. [1] [2]

I getestet, um die Leistung von Fileinputstream vs. Filechannel für Base64-codierte Dateien decodiert werden. In meinem experients testete ich ziemlich große Datei und traditionelle io war alle Tage ein bisschen schneller als nio.

einen Vorteil haben könnte in früheren Versionen des Jvm wegen synchonization Aufwand in mehreren io bezogenen Klassen

Filechannel hatte, aber die moderne Jvm ist ziemlich gut unnötige Sperren zu entfernen.

Wenn Sie nicht die transferTo Funktion oder nicht-blockierenden Eigenschaften verwenden Sie keinen Unterschied zwischen traditionellen IO und NIO bemerken (2), da die traditionelle IO Karten zu NIO.

Aber wenn man die NIO-Features wie transferFrom / To oder wollen verwenden können Puffer verwendet werden, dann natürlich NIO ist der Weg zu gehen.

Meine Erfahrung ist, dass NIO viel schneller mit kleinen Dateien ist. Aber wenn es um große Dateien kommt Fileinputstream / Outputstream ist viel schneller.

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