Java7: Faszination File AIO ...

T

tuxedo

Gast
Hallo zusammen,

ausnahmsweise hab ich mal keine Frage ...

Evtl. gehört's in die Plauderecke. Aber vom Thema her passt bei den "Java-Themen" schon...

Hab eben gerade ein wenig mit Asynchronous File IO in Java 7 gespielt...:applaus:
Und ich bin total geflasht.

Folgendes "sinnloses Test-Szenario":

HashMap<Integer, Long> mit 20Mio Einträgen wird in eine File "persistiert".

An den Anfang der File schreib ich noch in einem 8-byte Long die Größe der Hashmap.

Ergo:

8 byte + (20Mio * (4 byte Integer + 8 byte Long)) ...

Das sind also insgesamt 240000008 bytes, oder rund 240MB.
Geschrieben wird auf:

* Samsung SATA2 1TB Platte
welche hier drin steckt:
* Intel i7 860 4x2,8Ghz
* 8GB RAM
* Debian 6 AMD64

Damit ich nicht Byte-Weise schreibe, schreib ich immer 1Mio Einträge der HashMap (12byte/Eintrag) in einen ByteBuffer und schiebe den dann zum schreiben auf die Platte runter.

Und das dauert "wahnsinnige" 1196ms .... 20Mio Einträge mit 240MB... nur 1,2sek... *hammer* :toll:

Kein Plan wie ich 240B/sec mit der Platte erreichen soll. Wohlmöglich ist Java der meinung die Daten wären schon fertig geschrieben und ist "fertig mit Zeit messen", wobei das OS noch 1-2sekunden lang den Schreib-Puffer leert oder sowas...
Sehen kann ich die 1-2sek jedenfalls nirgendwo. Im Filebrowser sehe ich die File die 240MB erreichen qausi im selben Moment wie das Test-Programm fertig ist.


Egal. Interessant ist eben:

Kaum Aufwand in Java. Weder zeitmäßig noch implementierungsmäßig. Mit einem Profiler findet man eigentlich nix was man profilen könnte. Wird alles in den Tiefen, bzw. unterhalb der JVM erledigt.

Wer will da noch normales IO ???:L
 

c_sidi90

Top Contributor
240MB mit Java in 1,2 Sekunden. Da bin ich mal auf den Source gespannt, dass würde einige transaktionsgesteurte Ouputs vermeiden können. :D
 
T

tuxedo

Gast
So, hab noch ein wenig dran geschraubt und die File auch wieder probeweise eingelesen und den Inhalt verifiziert... Damit mir der Heap nicht gleich um die Ohren fliegt, musste ich von 20mio auf 10mio runter gehen: brauch jetzt 2 maps: eine initiell, die andere zum lesen (um einen vergleich zum zweiten befüllen zu haben).

Die Geschwindigekti ist aber nach wie vor die gleiche beim schreiben...

Hier der Source:

Java:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.Semaphore;

/**
 *
 * @author achr
 */
public class Java7FileAioTest {

    private int count = 10000000; // write a total of 10mio entries
    private int setSize = 12;
    private int blockFactor = 1000000;
    private ByteBuffer buffer = ByteBuffer.allocate(blockFactor * setSize); // write 1mio entries with 12 bytes each at once
    private final HashMap<Integer, Long> map1;
    private final HashMap<Integer, Long> map2;
    private Iterator<Integer> iterator;
    private AsynchronousFileChannel afc;
    private Semaphore sema = new Semaphore(1);
    long readMapSize = -1;
    long readPos = 0;
    long fileSize = -1;
    private long start;
    private long stop;
    private CompletionHandler<Integer, AsynchronousFileChannel> writeSetCompletion = new CompletionHandler<Integer, AsynchronousFileChannel>() {

        @Override
        public void completed(Integer result, AsynchronousFileChannel attachment) {
            writeSet(attachment);
        }

        @Override
        public void failed(Throwable exc, AsynchronousFileChannel attachment) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    };
    private CompletionHandler<Integer, AsynchronousFileChannel> readSetCompletion = new CompletionHandler<Integer, AsynchronousFileChannel>() {

        @Override
        public void completed(Integer result, AsynchronousFileChannel attachment) {
            readPos += result;
            readSet(attachment);
        }

        @Override
        public void failed(Throwable exc, AsynchronousFileChannel attachment) {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    };

    public Java7FileAioTest() {


        start = System.currentTimeMillis();
        map1 = new HashMap<>(count); // init hashmap mit voller größe --> geht dann schneller beim befüllen
        map2 = new HashMap<>(count); // init hashmap mit voller größe --> geht dann schneller beim befüllen
        stop = System.currentTimeMillis();

        System.out.println("Creating map: " + ((stop - start)/2) + "ms");

        long fillDuration = 0;
        long value = 0;
        for (int key = 0; key < count; key++) {
            if (key % 1000000 == 0) {
                System.out.println("Adding key: " + key);
            }
            start = System.nanoTime();
            map1.put(key, value);
            stop = System.nanoTime();
            fillDuration += (stop - start);
            value++;
        }
        System.out.println("Filling map takes " + (fillDuration / 1000000) + "ms");


        System.out.println("Start writing...");
        start = System.currentTimeMillis();
        writeToFile();
        stop = System.currentTimeMillis();
        System.out.println("Writing takes " + (stop - start) + " ms");
        System.out.println("Write-Speed: "+((double)fileSize/(double)((stop-start)/1000d))/1000000d+" mb/sec");

        map1.clear();

        System.out.println("Start reading + filling map...");
        start = System.currentTimeMillis();
        readFile();
        stop = System.currentTimeMillis();
        System.out.println("Reading+Filling takes " + (stop - start) + " ms");
        
        System.out.println("Start verifying...");
        start = System.currentTimeMillis();
        verify();
        stop = System.currentTimeMillis();
        System.out.println("Verifying takes " + (stop - start) + " ms");
    }

    private void writeToFile() {
        try {
            sema.acquire();
            File target = new File("/home/achr/HashMap.dat");
            if (!target.exists()) {
                target.createNewFile();
            }

            Path path = FileSystems.getDefault().getPath("/home/achr", "HashMap.dat");
            afc = AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);

            // single buffer for map size
            ByteBuffer bufferMapSize = ByteBuffer.allocate(8);
            bufferMapSize.putLong(map1.size());
            bufferMapSize.flip();

            // init iterator for later use in "write()" method
            iterator = map1.keySet().iterator();

            // initial write of map size
            afc.write(bufferMapSize, afc.size(), afc, new CompletionHandler<Integer, AsynchronousFileChannel>() {

                @Override
                public void completed(Integer result, AsynchronousFileChannel attachment) {

                    // delegate writing of map entries
                    writeSet(attachment);
                }

                @Override
                public void failed(Throwable exc, AsynchronousFileChannel attachment) {
                    throw new UnsupportedOperationException("Not supported yet.");
                }
            });

            // waiting for end of write
            sema.acquireUninterruptibly();
            sema.release();
            fileSize = afc.size();
            System.out.println("File has size: " + fileSize);
            // close file
            afc.close();

        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException | InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    private void writeSet(AsynchronousFileChannel afc) {
        boolean somethingToWrite = false;
        boolean endOfMap = false;
        buffer.clear();

        // fill complete buffer ...
        while (buffer.hasRemaining()) {

            // but only until end of map reached
            if (iterator.hasNext()) {
                Integer key = iterator.next();
                Long value = map1.get(key);
                buffer.putInt(key);
                buffer.putLong(value);
                somethingToWrite = true;
            } else {
                endOfMap = true;
                System.out.println("done writing.");
                break;
            }
        }
        buffer.flip();
        if (somethingToWrite) {
            try {
                afc.write(buffer, afc.size(), afc, writeSetCompletion);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        if (endOfMap) {
            // signal end of write to 'main'
            sema.release();
        }
    }

    private void readFile() {
        try {
            sema.acquire();

            Path path = FileSystems.getDefault().getPath("/home/achr", "HashMap.dat");
            afc = AsynchronousFileChannel.open(path, StandardOpenOption.READ);

            final ByteBuffer mapSizeBuffer = ByteBuffer.allocate(8);
            mapSizeBuffer.clear();

            afc.read(mapSizeBuffer, 0, afc, new CompletionHandler<Integer, AsynchronousFileChannel>() {

                @Override
                public void completed(Integer result, AsynchronousFileChannel attachment) {
                    if (result != 8) {
                        throw new RuntimeException("Not able to read map size");
                    }
                    readPos += result;
                    mapSizeBuffer.flip();
                    readMapSize = mapSizeBuffer.getLong();
                    System.out.println("map has size: " + readMapSize);

                    // trigger reading set
                    buffer.clear();
                    afc.read(buffer, readPos, afc, readSetCompletion);
                }

                @Override
                public void failed(Throwable exc, AsynchronousFileChannel attachment) {
                    throw new UnsupportedOperationException("Not supported yet.");
                }
            });

            // waiting for end of read
            sema.acquireUninterruptibly();
            sema.release();
            // close file
            afc.close();

        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }

    private void readSet(AsynchronousFileChannel afc) {
        buffer.flip();
        // get data from buffer
        for (int i = 0; i < blockFactor; i++) {
            int key = buffer.getInt();
            long val = buffer.getLong();
            map2.put(key, val);
//            System.out.println("Read: "+key+"/"+val);
        }

        if (readPos >= fileSize) {
            // signal end of read to 'main'
            sema.release();
        } else {
            // end not yet reached
            // delegate next read
            buffer.clear();
            afc.read(buffer, readPos, afc, readSetCompletion);
        }

    }
    
    private void verify() {
        boolean allOk = true;
        for(int i=0;i<count;i++) {
            Long value = map2.get(i);
            if (value==null){
                allOk = false;
                System.out.println("Key '"+i+"' is missing.");
            } else if (value.intValue()!=i) {
                allOk = false;
                System.out.println("Value for key '"+i+"' is wrong: "+value);
                break;
            }
        }
        if (!allOk) {
            System.out.println("Verification failed!");
        } else {
            System.out.println("Verification succeded!");
        }
    }

    public static void main(String[] args) {
        new Java7FileAioTest();
    }

}

Output auf meiner Kiste:

* Intel i7 860 4x2,8Ghz mit 8GB RAM
* Debian 6 AMD 64
* Oracle JDK7
* TB Samsung Platte SATA2, ext3 formatiert
* TestApp gestartet in NetBeans 7.1
* Nebenher noch tausend andere Dinge offen

Code:
Creating map: 19ms
Adding key: 0
Adding key: 1000000
Adding key: 2000000
Adding key: 3000000
Adding key: 4000000
Adding key: 5000000
Adding key: 6000000
Adding key: 7000000
Adding key: 8000000
Adding key: 9000000
Filling map takes 6196ms
Start writing...
done writing.
File has size: 120000008
Writing takes 609 ms
Write-Speed: 197.04434811165845 mb/sec
Start reading + filling map...
map has size: 10000000
Reading+Filling takes 5596 ms
Start verifying...
Verification succeded!
Verifying takes 253 ms

Ist mir selbst noch ein Rätsel wieso das so schnell gespeichert werden kann... Wenn jemand eine Erklärung hat: Her damit ...

Wer's selbst testen will und ggf. nicht genug Speicher hat: Einfach die "count" Variable ein wenig runterschrauben...

- Alex
 
Zuletzt bearbeitet von einem Moderator:
T

tuxedo

Gast
War/Ist ja auch meine Vermutung.

Aber das schmälert den Test nicht. Interessant ist nach wie vor dass man mit Java den Durchsatz hinbekommt.
Richtig interessant wird's jetzt mit einer schnellen SSD ...
 

tfa

Top Contributor
Man testet meist nur den Cache des OS anstatt den echten Durchsatz zur Platte ;)

Das wird's sein. Das OS cacht, die Festplatte eventuell auch.
Wenn ich in meinem frisch gestarteten Eclipse eine Volltextsuche über den ganzen Workspace mache, dauert das ca. 30 Sekunden. Die gleiche Suche danach nochmal gestartet dauert nur noch knapp 3 Sekunden. Cache ist schon was feines.
 

HoaX

Top Contributor
jup, das mit den Caches kann man schön unter Linux sehen wenn man z.B. "hdparm -tT /dev/sda" aufruft. Kenn den Effekt auch wenn ich Filme auf USB-Stick kopiere, die ersten ~300mb flutschen, dann stoppt es.
Falls du Linux benutzt kannst du ja mal direkt nach dem Schreiben das Programm "sync" ausführen lassen und die Zeit stoppen. sync sorgt für das leeren aller Schreibpuffer und kehrt erst dann zurück, wenn dies beendet ist.
 
T

tuxedo

Gast
Also bei den aktuellen 120MB die da geschrieben werden lässt sich mit "sync" nix rausmessen. Geht zu schnell. Müssten dann wohl schon mehr Daten sein, damit das, wie bei dir bei 300MB, anfängt zu stocken.

Windows wäre jetzt auch noch interessant zu sehen.
 

TheDarkRose

Gesperrter Benutzer
300MB sind auch noch wenig um wirklich die Festplatte zu testen. Müsstest schon wirklich damit anfangen ein paar GB zu schreiben. Oder du deaktivierst den Cache in den Mount Optionen.
 
T

tuxedo

Gast
Es ging ja nicht ums Platte testen. Es ging drum: Wieviel Durchsatz bekomm ich mit AIO und einer "normalen Platte" hin. Und so wie's ausschaut sind das aktuell um die 200MB/Sek. Mit normalen IO ist das sicherlich weniger bzw. braucht mehr Ressources (CPU, ...). Mit AIO ist das eben ein klacks.
 

njans

Top Contributor
PHP:
Creating map: 68ms
Adding key: 0
Adding key: 1000000
Adding key: 2000000
Adding key: 3000000
Adding key: 4000000
Adding key: 5000000
Adding key: 6000000
Adding key: 7000000
Adding key: 8000000
Adding key: 9000000
Filling map takes 4932ms
Start writing...
done writing.
File has size: 120000008
Writing takes 2232 ms
Write-Speed: 53.76344444444444 mb/sec
Start reading + filling map...
map has size: 10000000
Reading+Filling takes 3669 ms
Start verifying...
Verification succeded!
Verifying takes 2437 ms

bei:
* Intel Q6600 4x2,4Ghz mit 3GB RAM
* Win 7 x86 Premium
* Oracle JDK7
* Samsung HD321KJ Sata
* TestApp gestartet in Eclipse 3.7.1
* Nebenher noch tausend andere Dinge offen (und ein Download)
 
T

tuxedo

Gast
Interessant... Hab daheim auch einen Q6600 ... Muss da mal mit Debian 6 AMD64 gegentesten...
 
M

Marco01_809

Gast
Windows auf eine Crucial m4 64GB ~320 MB/s, auf eine WD Black 1TB ebenfalls ;)

Beide via SATA3 angeschlossen.
i5-2500K auf einem ASUS P8Z68-V PRO mit 4x4GB DDR3-1333
Windows 7 HP x64 SP1
Oracle JDK 7 Update 2
Gestartet in Eclipse 3.7.1

EDIT: Konsolenausgabe bei der SSD:
Creating map: 13ms
Adding key: 0
Adding key: 1000000
Adding key: 2000000
Adding key: 3000000
Adding key: 4000000
Adding key: 5000000
Adding key: 6000000
Adding key: 7000000
Adding key: 8000000
Adding key: 9000000
Filling map takes 4691ms
Start writing...
done writing.
File has size: 120000008
Writing takes 367 ms
Write-Speed: 326.9754986376022 mb/sec
Start reading + filling map...
map has size: 10000000
Reading+Filling takes 4486 ms
Start verifying...
Verification succeded!
Verifying takes 420 ms
 
Zuletzt bearbeitet von einem Moderator:

schalentier

Gesperrter Benutzer
Code:
Creating map: 29ms
Adding key: 0
Adding key: 1000000
Adding key: 2000000
Adding key: 3000000
Adding key: 4000000
Adding key: 5000000
Adding key: 6000000
Adding key: 7000000
Adding key: 8000000
Adding key: 9000000
Filling map takes 18263ms
Start writing...
done writing.
File has size: 120000008
Writing takes 745 ms
Write-Speed: 161.07383624161073 mb/sec
Start reading + filling map...
map has size: 10000000
Reading+Filling takes 12262 ms
Start verifying...
Verification succeded!
Verifying takes 1357 ms
bei:
* Intel Q9400 4x2,66Ghz mit 4GB RAM
* Win7 64 Home Premium
* Oracle JDK7, Update 2
* Samsung HD103SJ Sata
* gestartet in IntelliJ 11
* Nebenher noch mehrere tausend andere Dinge offen (und SW:TOR im Hintergrund)

Witzigerweise hoert man, wie die Platte aus dem Cache beschrieben wird, nachdem das Programm fertig ist - auch wenn die Datei bereits geloescht wurde ;-)
 

TheDarkRose

Gesperrter Benutzer
Es ging ja nicht ums Platte testen. Es ging drum: Wieviel Durchsatz bekomm ich mit AIO und einer "normalen Platte" hin. Und so wie's ausschaut sind das aktuell um die 200MB/Sek. Mit normalen IO ist das sicherlich weniger bzw. braucht mehr Ressources (CPU, ...). Mit AIO ist das eben ein klacks.

Aber nur in den Cache. Trotzdem kannst du nicht sagen, wie sich AIO wirklich beim schreiben auf die Platte verhält.
 
T

tuxedo

Gast
Aber nur in den Cache. Trotzdem kannst du nicht sagen, wie sich AIO wirklich beim schreiben auf die Platte verhält.

Ist das nciht meist egal? Wenn ich mit Java Daten schreiben muss/will, und Java meldet mir "Daten fertig geschrieben", dann kann ich sie mit Java auch wieder lesen. Mag sein dass das lesen dann etwas dauert wenn er mit schreiben noch nicht fertig ist. Aber alles in allem beschleunigt es doch meine Java Anwendung.
Aber gut, es mag konstellationen geben wo der Cache mehr stört wie nutzt... Mir ist so eine Konstellation allerdings noch nicht über den Weg gelaufen. Kommt vielleicht noch.

- Alex
 

TheDarkRose

Gesperrter Benutzer
Jo, dann hab ich wohl deinen Eingangspost etwas falsch intepretiert ;)


Festplattencache bzw. der Cache vom Betriebssystem selbst ist ein echter Spielverderber in einen RAID falls der Strom ausfallen sollte. Das eigentlich der einzige Fall wo der normale Cache stört.
 

LoR

Bekanntes Mitglied
Ich verstehe die ganze Aufregung darüber nicht. Außer das das Teil (AsynchronousFileChannel) jetzt zusätzlich einen CompletionHandler implementiert und noch ein paar kleinere (minimale) Features enthält gibts diese Funktionalität schon seit Java 5 (vgl. FileChannel). Wirklich interessant wirds eigeintlich nur in Bezug auf Sockets. Die können jetzt wesentlich leichter implementiert werden. Das ist aber auch schon alles.
 
T

tuxedo

Gast
Naja, nicht ganz. Bei NIO (reiner FileChannel) hast du selbst in einem Thread die Daten in die File schaufeln müssen. Bei AIO "schubst" du das nur an, und dann läufts von alleine (wenn du die CompletionHandler richtig miteinander verknüpft hast). Wenn ich die Semaphore nicht drin hätte, die wartet bis alles fertig ist, würde die Anwendung sofort terminieren.

Ein weiterer Vorteil von AIO: Da nicht aktiv von Java aus in die File geschrieben wird, kann ich mit meiner Anwendung auch keinen Puffer überlasten. Wird der überlastet, so wird der Java-Thread, der die Daten reinschreibt gebremst. Läuft ja alles synchron. Mit AIO fällt diese Bremsmöglichkeit meiner Anwendung weg. Und da es keinen Java-Thread braucht der die Daten schreibt, fallen auch (je nach File und Blockgröße) verdammt viele Thread-Kontext-Wechsel weg... Ergo: Mehr Zeit für's eigentliche...

- Alex
 

Kr0e

Gesperrter Benutzer
Ich sag doch AIO ist geil :D Neues kann auch mal gut sein :p

Ab JDK7 sind die ByteBuffer enorm verbessert worden. Find zwar grad nicht mehr die Quelle, aber kam direkt von Oracle. Man sollte nun stets direkte Buffer verwenden, da die interne Handhabung deutlich verbessert wurde. Somit könnte man ggf. sogar noch mehr rauskitzeln...
 
Zuletzt bearbeitet:

Empire Phoenix

Top Contributor
Bis auf das gc davon.. die is imernoch s******e

der cleart die directmemorys nur wenn der heap leerläuft.
alsow enn man meherer hundert megagbyte driect memory durchpumpt hat man ganz schnell mal ne exception dadurch.
 

Cola_Colin

Top Contributor
Code:
Creating map: 29ms
Adding key: 0
Adding key: 1000000
Adding key: 2000000
Adding key: 3000000
Adding key: 4000000
Adding key: 5000000
Adding key: 6000000
Adding key: 7000000
Adding key: 8000000
Adding key: 9000000
Filling map takes 12099ms
Start writing...
done writing.
File has size: 120000008
Writing takes 711 ms
Write-Speed: 168.77638255977496 mb/sec
Start reading + filling map...
map has size: 10000000
Reading+Filling takes 5673 ms
Start verifying...
Verification succeded!
Verifying takes 2923 ms

C2D E8400
4GB DDR2 800
Win7 Pro x64
Crucial m4 SSD 128GB

tjo, der Cache einer SSD ist wohl nicht schneller als der einer HDD ;)
 
M

maki

Gast
tjo, der Cache einer SSD ist wohl nicht schneller als der einer HDD
Vor allem hängen der Cache des Laufwerks hinter dem Cache des OS, und letzteres kann u.U. etwas inteligenter Cachen als ein Laufwerk welches nicht viel von Dateisystemen oder gar Dateien versteht ;)

Bei mir gibt es immense Schwankungen, je nachdem wie oft ich das laufen lasse.

zB. beim ersten mal:
Code:
Creating map: 49ms
Adding key: 0
Adding key: 1000000
Adding key: 2000000
Adding key: 3000000
Adding key: 4000000
Adding key: 5000000
Adding key: 6000000
Adding key: 7000000
Adding key: 8000000
Adding key: 9000000
Filling map takes 13254ms
Start writing...
done writing.
File has size: 120000008
Writing takes 715 ms
Write-Speed: 167.83217902097903 mb/sec
Start reading + filling map...
map has size: 10000000
Reading+Filling takes 11545 ms
Start verifying...
Verification succeded!
Verifying takes 3577 ms

ein paar male später dann (inkl. spielen mit Xms, Xmx und server Parameter)
Code:
Creating map: 48ms
Adding key: 0
Adding key: 1000000
Adding key: 2000000
Adding key: 3000000
Adding key: 4000000
Adding key: 5000000
Adding key: 6000000
Adding key: 7000000
Adding key: 8000000
Adding key: 9000000
Filling map takes 13165ms
Start writing...
done writing.
File has size: 840000056
Writing takes 752 ms
Write-Speed: 1117.0213510638298 mb/sec
Start reading + filling map...
map has size: 10000000
Exception in thread "Thread-1" java.nio.BufferUnderflowException
	at java.nio.Buffer.nextGetIndex(Buffer.java:498)
	at java.nio.HeapByteBuffer.getInt(HeapByteBuffer.java:355)
	at Java7FileAioTest.readSet(Java7FileAioTest.java:243)
	at Java7FileAioTest.access$1(Java7FileAioTest.java:239)
	at Java7FileAioTest$2.completed(Java7FileAioTest.java:51)
	at Java7FileAioTest$2.completed(Java7FileAioTest.java:1)
	at sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:126)
	at sun.nio.ch.SimpleAsynchronousFileChannelImpl$2.run(SimpleAsynchronousFileChannelImpl.java:336)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
	at java.lang.Thread.run(Thread.java:722)
k.A. woher die Exception kommt, könnte an meinem Setup liegen ???:L

"provisorisches" Ubuntu 10.04 32 Bit (läuft im Moment recht instabil, ist soz. mein "Not-OS") auf einem "alten" Quadcore 2,66GHz :)oops: weiss grad nicht genau...) mit irgendeiner alten & langsamen (5400 U/min, SATA Platte, 500 GB) Festplatte, Java 1.7.0 (build 1.7.0-b147).
 
Zuletzt bearbeitet von einem Moderator:

LoR

Bekanntes Mitglied
Naja, nicht ganz. Bei NIO (reiner FileChannel) hast du selbst in einem Thread die Daten in die File schaufeln müssen. Bei AIO "schubst" du das nur an, und dann läufts von alleine (wenn du die CompletionHandler richtig miteinander verknüpft hast). Wenn ich die Semaphore nicht drin hätte, die wartet bis alles fertig ist, würde die Anwendung sofort terminieren.

Ein weiterer Vorteil von AIO: Da nicht aktiv von Java aus in die File geschrieben wird, kann ich mit meiner Anwendung auch keinen Puffer überlasten. Wird der überlastet, so wird der Java-Thread, der die Daten reinschreibt gebremst. Läuft ja alles synchron. Mit AIO fällt diese Bremsmöglichkeit meiner Anwendung weg. Und da es keinen Java-Thread braucht der die Daten schreibt, fallen auch (je nach File und Blockgröße) verdammt viele Thread-Kontext-Wechsel weg... Ergo: Mehr Zeit für's eigentliche...

- Alex

Es braucht schon einen Thread. Der wird jetzt nur automatisch aus dem internen Threadpool genommen/erzeugt, wenn du keinen ExecutorService angibst. Wie gesagt die Funktionalität ist bereits lange enthalten, nur das du vorher den Thread selbst erzeugen und evtl einen eigenen Listener installieren musstest. Die Unterscheide sind aus meiner Sicht aber nicht besonders gross.
 

Kr0e

Gesperrter Benutzer
Nein, der Witz ist, dass der interne ThreadPool nur für die Ausführung des Listeners verantwortlich ist.
Das Lesen der Daten geschieht irgendwo tief im OS. Das wird auch gar nicht spezifiziert. Dennoch ist es möglich dass dies dort direkt geschieht. Wie Tuxedo bereits sagte, spart man sich da Thread-Kontextwechsel, die ziemlich teuer werden können, wenn man es häufig macht.


Hier werden viele Vorteile des neuen Konzepts im Zusammenhang mit dem Grizzly Framework näher beleuchtet: Parleys.com - The Next Generation E-Learning Platform

NIO1.4 mit den Selectors verkompliziert das wirklich nur. AIO macht genau das, was man in so einem Fall immer machen sollte, es überlässt dem OS die volle Kontrolle über das Lesen/Schreiben der Daten.

Unter Linux könnte es sogar noch aus anderen Gründen schneller sein. Laut der Doc wird bei AIO unter Linux epoll genutzt und bei NIO1.4 nur poll(). Zumindest in Jdk6, soweit ich mich errinnere. epoll ist in Etwa das Linux eigene AIO Konzept. Unter Windows wird AIO mit Overlapped I0 bzw. Completions Ports implementiert.

Alles in Allem ist es wirklcih Zeit, NIO1.4 aufzugeben. Selbst wenn AIO minimal langsamer wäre, würde ich AIO ab jetzt benutzen. Die Handhabung ist einfach super einfach im Gegensatz zu NIO1.4.

Gruß,
Chris
 

GUI-Programmer

Top Contributor
Also bei mir funktioniert es einfach nicht.

Mein System:
Betriebssystem: Windows 7 HomePremium 64 bit
Prozessor: Intel Core i5 650 @3.20 GHz
Arbeitsspeicher: 4 GB Ram
Grafikkarte: ATI Radeon HD 5700 Series

Ausgabe bei Start mit Java 1.7.0 32Bit:
Java:
Creating map: 37ms
Adding key: 0
Adding key: 1000000
Adding key: 2000000
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.HashMap.addEntry(Unknown Source)
	at java.util.HashMap.put(Unknown Source)
	at Java7FileAioTest.<init>(Java7FileAioTest.java:77)
	at Java7FileAioTest.main(Java7FileAioTest.java:282)

Ausgabe bei Start mit Java 1.7.0 65Bit:
Java:
Creating map: 19ms
Adding key: 0
Adding key: 1000000
Adding key: 2000000
Adding key: 3000000
Adding key: 4000000
Adding key: 5000000
Adding key: 6000000
Adding key: 7000000
Adding key: 8000000
Adding key: 9000000
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

Ach ja: Der Java Compiler ist 32 Bit (1.7.0).

Und unter Ecplise wurde komischerweise garnicht erst richtig kompiliert:
Java:
Exception in thread "main" java.lang.Error: Unresolved compilation problems: 
	Incorrect number of arguments for type HashMap<K,V>; it cannot be parameterized with arguments <?>
	Syntax error on token "<", ? expected after this token
	Incorrect number of arguments for type HashMap<K,V>; it cannot be parameterized with arguments <?>
	Syntax error on token "<", ? expected after this token
	IOException.InterruptedException cannot be resolved to a type
	Syntax error on token "|", . expected

	at Java7FileAioTest.<init>(Java7FileAioTest.java:64)
	at Java7FileAioTest.main(Java7FileAioTest.java:282)
 
Zuletzt bearbeitet:

Kr0e

Gesperrter Benutzer
Du brauchst die Codebasis 1.7. Sonst meckert der Compiler, da der Diamond Operator unbekannt ist.
Allerdings hat das nichts mit dem Out of Memory zu tun...
 
M

maki

Gast
Die Exception bei mir lag daran, dass ich die Datei HashMap.dat nicht gelöscht hatte zwischen den läufen :oops:
 

tfa

Top Contributor
Du brauchst eine aktuelle Eclipse-Version (3.7 Indigo).
Eclipse bringt seinen eigenen Compiler mit. Zusätzlich installieren musst du da nichts.
 

GUI-Programmer

Top Contributor
Du brauchst eine aktuelle Eclipse-Version (3.7 Indigo).
Eclipse bringt seinen eigenen Compiler mit. Zusätzlich installieren musst du da nichts.

Hab ich eigentlich auch. Zitat Eclipse:
Eclipse SDK

Version: 3.7.0
Build id: I20110613-1736

(c) Copyright Eclipse contributors and others 2000, 2011. All rights reserved.
Visit Eclipse Platform

This product includes software developed by the
Apache Software Foundation Welcome to The Apache Software Foundation!
 

Kr0e

Gesperrter Benutzer
Ich meine das ist erst ab 3.7.1... Eclipse hat ne weile gechillt, im Gegensatz zu Netbeans. Aber inzwischen sollte vollständiger Support da sein.
 

GUI-Programmer

Top Contributor
Das ist die erste Indigo-Version. Du brauchst die 3.7 SR1.

Eclipse Announces Full Support for Java 7

OK, Danke. Dann muss ich mir also nur noch unter Eclipse IDE for Java Developers die 64 Bit Version runterladen, richtig? Oder spreche irgendwas gegen die 32 Bit Version (außer dann üblichen Vorteilen einer 64Bit Version) ? Denn bei mir liegt die Downloadgeschwindigkeit momentan noch bei ca. 80 kB/s. Daher würde ich lieber nur 1x runterladen, damit ich diese auch für mein Netbook mit Windows 7 Starter nutzen kann.
 
Zuletzt bearbeitet:

GUI-Programmer

Top Contributor
OK, danke schon mal. Die Installation hat ohne Problem geklappt und der Compiler wurde umgestellt. Auserdem hab ich auch die Pfade für die "HashMap.dat" - Datei geändert:
[JAVA=110]File target = new File("C:/Users/MeinBenutzername/Desktop/HashMap.dat");[/code]
[JAVA=115]Path path = FileSystems.getDefault().getPath("C:/Users/MeinBenutzername/Desktop", "HashMap.dat");[/code]
Doch die Fehlermeldungen bleiben nach wie vor. Habe auch mal der Variable count den Wert 500000 verpasst, ändert aber nichts. Wo könnte der Fehler/das Problem also liegen?
 
T

tuxedo

Gast
Ich verstehe die ganze Aufregung darüber nicht. Außer das das Teil (AsynchronousFileChannel) jetzt zusätzlich einen CompletionHandler implementiert und noch ein paar kleinere (minimale) Features enthält gibts diese Funktionalität schon seit Java 5 (vgl. FileChannel). Wirklich interessant wirds eigeintlich nur in Bezug auf Sockets. Die können jetzt wesentlich leichter implementiert werden. Das ist aber auch schon alles.

Nein, der Witz ist, dass der interne ThreadPool nur für die Ausführung des Listeners verantwortlich ist.
Das Lesen der Daten geschieht irgendwo tief im OS. Das wird auch gar nicht spezifiziert. Dennoch ist es möglich dass dies dort direkt geschieht. Wie Tuxedo bereits sagte, spart man sich da Thread-Kontextwechsel, die ziemlich teuer werden können, wenn man es häufig macht.

Hab mal beim reinen lesen NIO mit AIO verglichen.

Hab in meinem AIO Sample beim lesen einfach das "put" für das füllen der Map weggelassen.
Lesezeit für die 120MB Daten: 53ms

Gleiches Beispiel mit NIO (aber mit Java7):

Java:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 *
 * @author achr
 */
public class NioRead {

    public static void main(String[] args) throws FileNotFoundException, IOException {

        int setSize = 12;
        int blockFactor = 1000000;
        ByteBuffer buffer = ByteBuffer.allocate(blockFactor * setSize); 

        long start = System.currentTimeMillis();
        File f = new File("/home/achr/HashMap.dat");
        RandomAccessFile ram = new RandomAccessFile(f, "r");
        FileChannel channel = ram.getChannel();
        ByteBuffer sizeBuffer = ByteBuffer.allocate(8);
        channel.read(sizeBuffer);
        sizeBuffer.flip();
        long size = sizeBuffer.getLong();

        for (int i = 0; i < 10; i++) {
            channel.read(buffer);
            buffer.flip();
            for (int ii = 0; ii < blockFactor; ii++) {
                int key = buffer.getInt();
                long val = buffer.getLong();
//                System.out.println(key+" -> "+val);
            }
        }
        long stop = System.currentTimeMillis();
        System.out.println("Time taken to read: " + (stop - start) + "ms");
    }
}

Dauer: ca. 75ms.

Beim blockweisen lesen ist AIO ein klein wenig im Vorteil was die Geschwindigekti angeht. NIO ist hier nicht nur langsamer (ein klein wenig), sondern auch, ressourcenhungriger.

Ich denke wenn man nicht in großen Blöcken liest ist der Unterschied der geschwindigkeit zwischen AIO und NIO noch kleiner. Müsste man mal testen.

[EDIT]Hmm, okay. Meine Vermutung stimmt nicht ganz.

Seltsamerweise ist AIO beim lesen von 12byte großen Blöcken schneller:

12byte blöcke: 9ms
12000000byte blöcken: 53ms.

Vergleich zu NIO:

12byte blöcke: 1702ms
12000000byte blöcke: 75ms

So oder so: AIO ist überlegen.
[/EDIT]
 
Zuletzt bearbeitet von einem Moderator:
T

tuxedo

Gast
Doch die Fehlermeldungen bleiben nach wie vor. Habe auch mal der Variable count den Wert 500000 verpasst, ändert aber nichts. Wo könnte der Fehler/das Problem also liegen?

Du musst in Eclipse einstellen welche Java-Version du für das Projekt benutzt. Daneben musst du noch das JDK7 installiert haben, sowie Eclipse beigebracht haben, dieses JDK7 auch zu benutzen (geht in den Preferences bei den JREs).

Oder du benutzt halt Netbeans ;-)
 

Kr0e

Gesperrter Benutzer
Aber auch wenn AIO minimalst langsamer wäre... Ich mag einfach die einfache Handhabung im Gegensatz zu NIO. Aber da es schneller ist, umso besser :p
 
T

tuxedo

Gast
Naja, beim File-IO gibt sich's nicht viel. Finde beides da sehr einfach. NIO ist nur ein klein wenig "einfacher/logischer". Mit AIO muss ich immer nochmal drüber nachdenken wierum das jetzt gehört: Die indirektion durch den CompletionHandler macht mir hin und wieder einen Knoten in die Hirnwindungen. Bin vielleicht aber auch schon zu viel mit normalem IO unterwegs gewesen. Nach weiteren 1-2 Tagen AIO wird das aber wohl verschwinden.

Beim Netzwerk-IO geb ich dir allerdings vorbehaltlos recht. Da ist NIO echt kompliziert und AIO eine echte Wohltat.
 

GUI-Programmer

Top Contributor
Hat vielleicht noch irgendjemand eine Idee, warum es bei mir nicht geht? Die Systemdaten hab ich ja bereits mitgeteilt. Ich hab auch schon versucht irgendwas über den Cache meiner Festplatte zu erfahren, bin aber gescheitert. Also wenn irgendjemand noch einen Vorschlag hat, dann her damit. Denn schließlich geht das Programm ja bei allen anderen.
 

bERt0r

Top Contributor
Naja, eure Wahnsinnszeiten liegen aber wohl auch an euren Hightech computern. Auf meinem 4 Jahre alten Laptop hat man einen viel "normaleren" Datendurchsatz ;D
Code:
Creating map: 86ms
Adding key: 0
Adding key: 1000000
Adding key: 2000000
Adding key: 3000000
Adding key: 4000000
Adding key: 5000000
Adding key: 6000000
Adding key: 7000000
Adding key: 8000000
Adding key: 9000000
Filling map takes 13808ms
Start writing...
done writing.
File has size: 120000008
Writing takes 4993 ms
Write-Speed: 24.033648708191464 mb/sec
Start reading + filling map...
map has size: 10000000
Reading+Filling takes 6318 ms
Start verifying...
Verification succeded!
Verifying takes 2653 ms
 
T

tuxedo

Gast
Hast du evtl noch Virenscanner und Co. laufen? Die bremsen für gewöhnlich den Transfer mächtig ab.
Evtl. hast du auch ne langsame, energieparende Festplatte mit 5400RPM und wenig bis kein Cache oder sowas.

Weil mein zweiter Testrechner hier ist auch 4 Jahre alt, aber wurde "damals" mit guter Hardware bestückt...Und da läufts auch super schnell.
 

GUI-Programmer

Top Contributor
Irgendjemand noch ne Idee???

Wie bereits gesagt: Compiler und Virtuelle Maschine passen, und auch der Pfad, aber dennoch die beschriebene Fehlermeldung, sowohl wenn ich es per Eclipse kompiliere und ausführe als auch wenn ich es per Konsole kompiliere und ausführe.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
VfL_Freak JDK installieren Problem mit Erstellungspfad nach Wechsel von Java7 auf Java8 Allgemeine Java-Themen 1
W Jar-File Start nur über Terminal Allgemeine Java-Themen 13
R 11 GB File lesen ohne zu extrahieren Filedaten Bereich für Bereich adressieren dann mit Multi-Thread id die DB importieren Allgemeine Java-Themen 3
D Read JSON File Problem Allgemeine Java-Themen 9
S Umstellung von File auf Path - Probleme mit Stream Allgemeine Java-Themen 5
C jar File mehrfach aufrufen (als Windows Dienst) Allgemeine Java-Themen 5
N File Path mit Variablen angeben Allgemeine Java-Themen 1
izoards Zugriff auf gemeinsame Ressource (CSV-File) Allgemeine Java-Themen 3
S Class File Editor -> Source not found Allgemeine Java-Themen 4
F jar File ausführen Allgemeine Java-Themen 14
M File Binary Representation Allgemeine Java-Themen 1
N jar File auf Mac mit Doppelklick starten Allgemeine Java-Themen 5
O Input/Output java.io.File beenden Allgemeine Java-Themen 5
G File not found - nach dem Kompilieren Allgemeine Java-Themen 6
T Jar File zu exe... Allgemeine Java-Themen 3
M Foreign Memory API / Memory-Mapped File Allgemeine Java-Themen 0
R Delete files before creating new from temp using Java file method Allgemeine Java-Themen 1
S File lesen und schreiben Java 6 Allgemeine Java-Themen 2
T String-Manipulation beim Ablauf in Eclipse und als JAR-File Allgemeine Java-Themen 8
F Input/Output FileNotFoundException, obwohl File existiert Allgemeine Java-Themen 5
G Excel File öffnen, in Zelle schreiben, abspeichern Allgemeine Java-Themen 6
L JAR-File auf Ilias (LMS) laufen lassen Allgemeine Java-Themen 0
ralfb1105 Classpath Directory fuer Properties File Allgemeine Java-Themen 2
L File beim Kopieren in einen anderen Ordner umbenennen Allgemeine Java-Themen 6
J File in Package erstellen & lesen mit Programmstart in externe Projekt Allgemeine Java-Themen 3
I File ausführen und mein Programm bearbeiten lassen Allgemeine Java-Themen 11
A File lesen Codierung Charset Allgemeine Java-Themen 5
J .java-Dateitext Compile zur Laufzeit ohne File Allgemeine Java-Themen 15
M Key-File im selben Ordner speichern? Allgemeine Java-Themen 18
I TrueZip add file to archive Allgemeine Java-Themen 10
T Probleme mit dem Pfad zum Propertie file Allgemeine Java-Themen 7
J ftp - delete file ohne appache Allgemeine Java-Themen 8
X Klassen File-Klasse wird als Directory markiert Allgemeine Java-Themen 8
T ImageIO.read -> Can`t read input file Allgemeine Java-Themen 11
L Applet Problem "security: Trusted libraries list file not found" ? Allgemeine Java-Themen 7
C Swing File[] als klickbare links in irgendeinem Swing Element Allgemeine Java-Themen 3
H Kennt sich jemand mit Eclipse und dem Thema Jar-File aus ? Allgemeine Java-Themen 6
H Laden einer (Resourcendatei) aus einem Jar-File Allgemeine Java-Themen 17
C Authentifizierung mit java.nio.file? Allgemeine Java-Themen 5
L CSV File lesen, in ArrayList speichern und ausgeben Allgemeine Java-Themen 3
M xlsx File auslesen Exception occured Allgemeine Java-Themen 13
offi Drag and Drop mehrerer File aus Explorer in JTable Allgemeine Java-Themen 1
G Java/LibGDX File Loading Exception Allgemeine Java-Themen 2
Cromewell JavaFX FXML-File lädt unter Ubuntu nicht Allgemeine Java-Themen 7
D Java Anwendung mit dll File Allgemeine Java-Themen 5
AssELAss Log4j Logging Ausgabe für jede Klasse in seperates File Allgemeine Java-Themen 2
thet1983 Input/Output read properties file from classpath Allgemeine Java-Themen 3
J Umwandeln von URL zu File und danach kopieren geht nicht Allgemeine Java-Themen 1
J Properties file ändern Allgemeine Java-Themen 12
S Executable Jar File startet nicht unter Windows 10 Allgemeine Java-Themen 3
B Objekte anhand von Properties file Allgemeine Java-Themen 41
Dechasa Input/Output Write into File Allgemeine Java-Themen 2
N Maven ObjectMapper Error wenn das File gespeichert wird Allgemeine Java-Themen 0
H Security Manager (IIOException: Can't read input file!) Allgemeine Java-Themen 2
H File.listFiles() funktioniert nicht... Allgemeine Java-Themen 10
C Input/Output Problem bei Datei verschiebung mit File.move und Paths.get() Allgemeine Java-Themen 26
X Zeile unter einer bestimmen Zeile hinzufügen(File) Allgemeine Java-Themen 1
F Open source file übersetzen Phython -> Java Allgemeine Java-Themen 4
C file.delete() funktioniert bei zweiten aufruf nicht mehr Allgemeine Java-Themen 3
M Desktop jar File icon Ändern? Allgemeine Java-Themen 14
O Sax-Parser ließt XML-File doppelt Allgemeine Java-Themen 1
J Java Software Compare Files und Neue File erstellen Allgemeine Java-Themen 0
Thallius Custom File Chooser Allgemeine Java-Themen 1
C .jar File lässt sich nur über Konsole öffnen Allgemeine Java-Themen 1
J Java Download Filedownload File.getFileName Allgemeine Java-Themen 3
R Java .class-File-Konstrunkt mit Programm visualisieren Allgemeine Java-Themen 18
G SecurityManager/Policy-File/Reflection Allgemeine Java-Themen 0
M pdf File bzw. ausgefüllte pdf Formulare drucken Allgemeine Java-Themen 2
S Input/Output File Not Found FileReader Allgemeine Java-Themen 6
Thallius Serialisiertes File kann auf anderem Rechner nicht geladen werden Allgemeine Java-Themen 12
P Java Dynamic Web Project -> config File Allgemeine Java-Themen 1
S runnable jar file in Verbindung mit itext Allgemeine Java-Themen 3
D Variablen java.io.File zum vergleichen abspeichern Allgemeine Java-Themen 1
M File IO Klasse ... wie einbinden Allgemeine Java-Themen 6
O Freies Tool zum Jar-File obfuscaten gesucht! Allgemeine Java-Themen 5
F File.listFiles ohne .sort Allgemeine Java-Themen 6
B XML File JAXB Allgemeine Java-Themen 0
S Platzverbrauch, File oder String Allgemeine Java-Themen 14
J Runnable jar-File: Fehlermeldung Allgemeine Java-Themen 2
P Kurze Frage: aus einer File die Zeilenanzahl auslesen Allgemeine Java-Themen 9
K Gepacktes Jar-File gibt beim Doppelklick eine Exception aus Allgemeine Java-Themen 4
P java.nio.file unter Java 6 verwenden Allgemeine Java-Themen 4
A TXT File einlesen unterschiedliche Zeilenlänge Allgemeine Java-Themen 9
B Finde letztes veränderte File Allgemeine Java-Themen 4
E Zip-File entpacken: unterschiedlicher Zeitaufwand bei unterschiedlicher Puffergröße Allgemeine Java-Themen 2
Guybrush Threepwood File.canWrite() und UAC Allgemeine Java-Themen 7
N Input/Output Mit Windows 7 erzeugtes zip-File in Java 7 öffnen Allgemeine Java-Themen 5
B Garbage Collection Logfile: Binary File Allgemeine Java-Themen 2
H XML-File mit Java erzeugt Frage Allgemeine Java-Themen 10
V C-Header Datei aus .java File herstellen Allgemeine Java-Themen 10
D File mit Inhalt kopieren und dieses File dann neu erstellen ? Allgemeine Java-Themen 4
T @NotBlank verwendet nicht message aus .property-File Allgemeine Java-Themen 4
G Jar-File soll eignen *.jar Namen ausgeben Allgemeine Java-Themen 10
S Jar-File startet nicht über doppelklick Allgemeine Java-Themen 2
P ganze Zeilen in einem File mit .replace() ändern. Allgemeine Java-Themen 10
S Datei in File-Objekt mit UTF-8 einlesen Allgemeine Java-Themen 2
P Aus einem File Zeilen auslesen. Allgemeine Java-Themen 15
V ProcessBuilder exe file Allgemeine Java-Themen 3
L Variablen IO Exception weil File angeblich nicht exisitert Allgemeine Java-Themen 10
M File einlesen während es beschrieben wird.. Allgemeine Java-Themen 6

Ähnliche Java Themen

Neue Themen


Oben