Eclipse IDE und Quad core


#1

Hallo zusammen,

ich stehe vor der Frage ob ich einen i7 Quad Core Prozessor brauche oder ein i5 Dual Core reicht.

Hauptsächlich programmiere ich und normale Office Arbeit, hin und wieder mal ein Bild bearbeiten.

Würde eclipse beim Dateien einlesen, etc überhaupt 4 Kerne ansprechen? Speziell dauert mir das einlesen von 100mb großen csv und Textdateien zu lange.

Es steht aber schon fest es wird ein MacBook. Nur i7 oder i5?

Kennt ihr euch damit aus? Wann macht ein i7 sind wohl nur bei Video und co?


#2

Mir eigentlich auch. Als Blob oder “sequentiell”, also “strömend”? Wie stellst du dir das einlesen mit 4 Kernen so vor, also die parallelisierung?

Man muss zuerst herausfinden, was der langsame teil dabei ist.

Der i7 besser - aber ich würd nicht generell abraten.


Strings in Java langsam. :roll_eyes: Zumindest was betrifft “very ‘ridiculously’ large files”…


#3

Keine Ahnung warum das so langsam ist , der Prozessor soll sich darum kümmern. Wenn ich das gleiche auf m Server ausführe mit 8 lernen, geht das unter 4 Minuten, Lokal dauerte ne halbe Stunde


#4

Wenig Kontext. Etwas oberflächlich gesagt wird die Zeit zum Einlesen einer Datei hauptsächlich von der Festplatte abhängen (SSD?). Ansonsten passiert das ja nur in einem Thread, d.h. die Anzahl der Kerne sollte da keine Rolle spielen. Allgemein aber schon langsam. Viele streuen ja neuerdings mal locker-flockig aus dem Handgelenk ein stream.parallel() irgendwo rein, ~“damit es schneller wird” :wink:


#5

Fuer die Kompilierung von Java Dateien braucht man keine 20 Kerne, einer reicht (solange man die Module nicht parallel baut), die Platte sollte schnell sein, am besten SSD, und falls man Windows nutzt, nicht vergessen dem Virenscanner zu untersagen alle .class Dateien zu scannen.
Falls man Scala kompilieren will, dann mindestens 256GiB RAM und 64 Kerne :clown_face:

Na dann nimm doch den i7 weil: Schneller und Groesser :wink:


#6

Nein, leider nicht richtig das ist. Ich verarbeite solche “very ‘ridiculously’ large files”, auch mit 'ner SSD… Der langsame part ist dabei wirklich: zeilenweise einlesen, zeilenweise Strings erstellen, Zeilen splitten, Strings/Spalten in Datentypen wie float usw. umwandeln, ggf eine Validierung (und Skip/Berichtigung) dabei mit try-catch vornehmen, Daten-Objekte erstellen, Daten-Objekte in einer Collection sammeln.

Die Lesegeschwindigkeit ist weit mehr als 100mb/s der SSD, aber der Prozessor für einen Kern auf Volllast ist, das bedeutet, der langsame part ist wirklich das zeilenweise/zeichenweise…

Auch beim zweiten Mal wird durch das OS die SSD gar nicht mehr gelesen - aber die Geschwindigkeit ist gleich-geblieben.

Man könnte vielleicht den BufferedReader durch RawStreams vermeiden, aber ob man das möchte?


#7

Cyborg stimmt ich voll zu, mache exakt das selbe mit meinen Dateien, also einlesen, splitten Objekte erstellen, sammeln usw. dabei läuft er nahezu unter volllast aber da der aktuelle i5 Prozessor von 2012 ist, vielleicht ist die aktuelle Generation besser? Denn das einlesen findet ja Tatsache nur in einem Thread der jvm statt. Das könnte man doch gar nicht auf mehrere Threads verteilen?! Und ob die cpu 2 Java Threads in 2 Kerne steckt bezweifle ich auch irgendwie, vielleicht 2 virtuelle

Will mit nur keinen super teuren i7 kaufen um dann zu merken, dass es raus geschmissenes Geld war


#8

Joa, wenn ich die Antwort anfange mit “Wenig Kontext”, dann bedeutet das unter anderem, dass man ja nicht weiß, ob jemand

String line = bufferedReader.readLine();
while (true) System.out.println(line);

macht. Natürlich dauert da das Lesen nicht so lange, wie das, was danach kommt :roll_eyes:


Wenn man mehr Details hat, kann man fundiertere Aussagen machen. Das Einlesen einer einzelnen Datei ist (außer, wenn man sehr viel Aufwand reinsteckt, der sich oft aus verschiedenen (technischen) Gründen in diesen Fällen nicht lohnt) praktisch immer single-Threaded.

Wenn das, was mit den eingelesenen Daten gemacht werden soll, “rechenaufwändig” ist, kann man sicher was machen. (“Rechenaufwändig” könnte (!) hier schon ein Float.parseFloat sein).

Ganz grob: Sowas hier wird man kaum schneller machen können:

List<Point3D> points = new ArrayList<Point3D>();
while (true) {
    String line = bufferedReader.readLine();
    if (line==null) break;

    String tokens[] = line.split(someComplexRegEx); // Evtl. rechenaufwändig
    float x = Float.parseFloat(tokens[0]); // Relativ (!) rechenaufwändig
    float y = Float.parseFloat(tokens[1]); // Relativ (!) rechenaufwändig
    float z = Float.parseFloat(tokens[2]); // Relativ (!) rechenaufwändig
    Point3D point = new Point3D(x,y,z);
    point.normalize(); // Relativ (!) rechenaufwändig
    points.add(point);
}

Und auch ganz grob: In solchen Fällen könnte es schneller sein, sowas zu machen:

List<String> lines = Files.readAllLines(path);
List<Point3D> points = lines.stream()    // ??? .parallel() ??? Siehe unten!
    .map(lineToTokens)
    .map(tokensToPoint)
    .map(pointToNormalizedPoint)
    .collect(toList());

Also erstmal mit Files#readAllLines alles zu lesen (das hängt dann praktisch nur noch an der Geschwindigkeit der Festplatte!). Danach kommt das, wo gerechnet werden muss. Und da könnte man, wennn man das parallel() einfügt, ggf. auf einem 4-Kerner mehr rausholen als auf einem 2-Kerner.

Aber das ist alles sehr suggestiv. Es könnte sein, dass es besser wäre, das ganze nicht parallel zu machen, sondern direkt auf dem Stream von Files#lines zu arbeiten.

Um Messen und Benchmarks kommt man da kaum drumrum. Um welchen Preisunterschied geht es denn bei dem i5 vs. i7 grob?


#9

Hi Marco Danke für deine ausführliche Antwort. Ich Lesens wie in deinem ersten Code Schnipsel.

i7 kostet gut 300 mehr da es den im 15 zoll Mac Book gibt. Wenn nicht sogar noch mehr Unterschied hat. Ich denke auch das dass lesen in einem Kern passiert. Mehrere Dateien gleichzeitig geht ja indem man es in einem eigenen Thread auslagert


#10

Das ist prinzipiell möglich. Aber man muss damit rechnen, dass das gleichzeitige Lesen mehrerer Dateien (oder einer Datei) mit mehreren Threads langsamer ist, als das sequentielle Lesen. Vor allem bei HDDs, aber auch bei SDDs, ist sequentielles lesen oft deutlich schneller, als wenn “kreuz und quer” an verschiedenen Stellen gelesen werden muss. Muss man benchmarken.


#11

Ok also würdest du prinzipiell keinen Vorteil im i7 sehen wenn es um das lesen geht?


#12

Hi,

also zunächst einmal möchte ich behaupten, dass das Problem hier nicht das “Einlesen” ist, sondern eher das Verarbeiten.
So wie ich das hier mangels Beispiel zwischen den Zeilen heraus gelesen habe, ist der Ansatz die Daten zu Verarbeiten recht naiv, nämlich mittels String Operationen. Das Einlesen und die Verarbeitung passiert in einem Schritt und kann nur schwer parallelisiert werden. - Klar.

Das ganze dann mittels Hardware zu kompensieren finde ich schwer. 100 MB CSV Dateien finde ich auch nichteinmal viel… Unser “Briefdaten” werden mittels CSV mit Druckdienstleistern ausgetauscht. Wenn ich 100.000 Briefe schicken möchte mit Adressen, Texten und ggf. weiteren Informationen, dann kommen schnell 100 MB zusammen. (Hauptsächlich auch deshalb, weil pro Zeile recht viele “generische” Informationen enthalten sind, die für einige Briefe notwendig sind aber eben nicht für alle ^^). Wie dem auch sei, konnte ich nicht beobachten, dass dies 8 Minuten dauert diese Dateien zu verarbeiten.

Ich würde daher prüfen, ob mein Konzept und die Implementierung korrekt sind. Das Einlesen würde ich von der Verarbeitung trennen, denn jede Zeile in einer CSV ist unabhängig und kann daher (normalerweise) gut parallelisiert werden.

Das Einlesen selber würde ich zunächst mit einem Lexer probieren, um zu schauen, ob das schneller ist. I.d.R. reicht es aus apache CSV PArser zu verwenden. Siehe hier, wie er die Zeilen interpretiert:

Um das besser bewerten zu können, müsste man wissen, wie die CSV aufgebaut ist und wie man diese verarbeitet.

Ob du dir nun ein I7 oder I5 kaufst, ist denke ich für das aktuelle Problem irrelevant, denn da ist der Bottleneck imho nicht die CPU. Ich persönlich würde auch zum i7 greifen. - Habe ich in jedem Rechner und in meinem privaten bereits seit über 8 Jahren. Ich habe bisher nicht festgestellt, dass ich da nun einen neuen brauche, daher ist meine Empfehlung: Besser die bessere Hardware, als später schneller upgraden.


#13

+ 1. Nicht so zögerlich sein…

Leider falsch. In dem Fall ist der Engpass der Prozessor. Ein imho ist auch nicht angebracht.

Suggestivieren wir einmal, das ein paar 100mb große File wäre 2gb groß. Das ganze Handling mit Strings ist der Engpass.

Nun glaub’ das doch mal einem, der diese Datenmengen verarbeitet. :smile:


Zum i7… Wenn neu, dann relativ bis absolut neu, das würd ich auch sagen.

Nur es gibt halt nicht nur den i7.


#14

Woher weißt du, dass das falsch ist? - Ich habe ja dargelegt, wieso es genau nicht die CPU ist.

Was genau ist an imho “nicht angebracht”?

Negativ. Leider ist dein Skill, den du hier gezeigt hast, für solche Aussagen nicht ausreichend. Sorry.


#15

In der Regel lässt sich zu bestimmten Prozessoren auch immer ein passender Benchmark finden.
Aber sollte ein i7 die Doppelte Punktzahl bekommen im Vergleich zum i5, dann würde dein Programm, wenn es daran läge auch nur in der halben Zeit fertig. Um welche CPUs geht es denn überhaupt? Und wie schneiden diese bei Passmark ab? Ich schätze, dass die sich nicht so grossartig Unterscheiden.

100 MB/s ist etwa die Leserate einer normalen HDD. SSD liegt bei Rund 500 MB/s. Gibt natürlich auch Abweichungen, je nach Anschluss. Über USB 2.0 kommen meist nicht mehr als 20 MB/s durch. Das lesen alleine sollte also im Bereich von einer Sekunde liegen.

Von daher kann man bei 100 MB Dateien und über 4 Minuten schon mal abschätzen, dass das Lesen alleine nicht unbedingt der Flaschenhals sein muss, sofern man hier nichts wesentliches falsch macht. Das sollte man aber auch gut messen könne, wenn man sich zum Beispiel als erstes eine Liste von Strings erstellt.

Darüber hinaus sollte man auch nachmessen ob und wo genau die Rechenzeit verloren geht. An den richtigen Stellen optimiert, kommt da oft mehr dabei raus, wie bei neuer Hardware. Dafür muss man aber auch einen Profiler verwenden.

Es stellt sich auch die Frage, wie sich Entwicklungsrechner und Server unterscheiden. Andere JVM, andere Parameter, anderes Betriebssystem, anderer GC. Auch dies, so unscheinbar es sein mag, kann viel ausmachen.

Selbst Files::readAllLines kann im Gegensatz zu einem BufferedReader Ansatz Ärger machen, wenn ersteres erstmal den Speicher komplett vollschreibt um dann den GC loszulassen der unnützes versucht wieder freizuräumen wohin das andere resourcenschonender vorgehen kann.

Aber alles nur Vermutungen.


#16

Das verwendet intern einen BufferedReader :smiley:

Aber allgemein stimmt das natürlich: Man kann hier lange spekulieren. Die ursprüngliche Frage war ja, etwas vereinfacht, ob es sich lohnt, mehr für einen Prozessor auszugeben, damit eine CSV schneller gelesen werden kann, und die Quintessenz ist: Das hat damit nicht unbedingt viel zu tun…


#17

Das frag’ ich mich gerade auch. Ich hab zwar einen Verdacht, aber dass es nur um den i7 und i5 geht würd ich auch nicht vermuten. - Insgesamt doch relativ viel “Suggestivität” in diesem Thema. :slight_smile:


#24

Ich würde denken, dass es zwei Dinge sind, die man betrachten muss. Alleine gesehen, ist dieses Programm, das hier beschrieben wird, nicht allzu rechenintensiv und der limitierende Faktor ist eher IO, sprich die Festpatte. Ich würde vermuten, wenn man das Programm auf zwei Rechnern, die ein minimales Linux System mit gleichem RAM und gleicher Festplatte/SSD haben, laufen lässt, es bei solchen Datenmengen (mehrere 100 MB), kaum einen Unterschied ausmacht.

Da aber @NicoDeluxe explizit nach MacOS und Eclipse fragt, würde ich behaupten, dass der Unterschied schon spürbar ist. Auf Desktopsystemen laufen zig Hintergrundprozesse, Eclipse ist relativ speicherhungrig und dann hat man vielleicht noch einen Browser offen, das kostet alles.


#25

Lies doch erstmal nur die Dateien in den Arbeitsspeicher bevor du sie verarbeitest und schau ob das akzeptabel lange dauert.

Die CPU hat eigentlich nix mit HD/RAM Operations am Hut, das macht der Chipsatz auf dem Board. (Und Java hat damit auch nix am Hut, außer dem OS zu sagen: lad mal byte-menge und gib Bescheid wenn fertig).
Wenn dann liegt das an der Anzahl einzelner Dateien, damit können HDDs nähmlich nicht umgehen - oder deine Definition von “zu lange”.

Bei uns läuft ein Programm mit 32 Threads auf einem 4-Kerner Intel Xenon mit HDD, das jagt täglich ca. 500-600 ca. 10 mb große XML Dateien innerhalb von 20 Sekunden durch den Parser und verarbeitet sie (String Operationen).
Das ist 1,5 Billiarden mal schneller als die Daten per Hand zu verarbeiten und meine Definition von schnell genug. :wink:


#26

Hier ist mal der Beweis:

class IstEsDieCPU_FRAGEZEICHEN {

    public static void main(String[] args) throws IOException, InterruptedException {
        long t1 = System.currentTimeMillis();
        CSVgenerierenUndSpeichern();
        long t2 = System.currentTimeMillis();
        Thread.sleep(5000);
        System.out.println("Runtime.getRuntime().totalMemory() = " + Runtime.getRuntime().totalMemory() / (1024 * 1024));
        System.out.println("Runtime.getRuntime().maxMemory() = " + Runtime.getRuntime().maxMemory() / (1024 * 1024));
        System.out.println("Runtime.getRuntime().freeMemory() = " + Runtime.getRuntime().freeMemory() / (1024 * 1024));
        System.out.println();

        long t3 = System.currentTimeMillis();
        ByteArrayInputStream BuArrayOutputStreamToBuArrayInputStream = BuArrayOutputStreamToBuArrayInputStream(AlsBlobLaden());
        long t4 = System.currentTimeMillis();
        Thread.sleep(5000);
        System.out.println("Runtime.getRuntime().totalMemory() = " + Runtime.getRuntime().totalMemory() / (1024 * 1024));
        System.out.println("Runtime.getRuntime().maxMemory() = " + Runtime.getRuntime().maxMemory() / (1024 * 1024));
        System.out.println("Runtime.getRuntime().freeMemory() = " + Runtime.getRuntime().freeMemory() / (1024 * 1024));
        System.out.println();

        long t5 = System.currentTimeMillis();
        NUR_AUSRUFEZEICHENAUSRUFEZEICHENAUSRUFEZEICHEN_Parsen(BuArrayOutputStreamToBuArrayInputStream);
        long t6 = System.currentTimeMillis();
        Thread.sleep(5000);
        System.out.println("Runtime.getRuntime().totalMemory() = " + Runtime.getRuntime().totalMemory() / (1024 * 1024));
        System.out.println("Runtime.getRuntime().maxMemory() = " + Runtime.getRuntime().maxMemory() / (1024 * 1024));
        System.out.println("Runtime.getRuntime().freeMemory() = " + Runtime.getRuntime().freeMemory() / (1024 * 1024));
        System.out.println();

        System.out.println("Schreiben: " + (t2 - t1));
        System.out.println("Lesen:     " + (t4 - t3));
        System.out.println("Parsen:    " + (t6 - t5));
    }

    private static void CSVgenerierenUndSpeichern() throws FileNotFoundException {
        Random random = new Random();
        try (PrintWriter printWriter = new PrintWriter(new BufferedOutputStream(new FileOutputStream("csv.txt")))) {
            for (long i = 0; i < 62_000_000; i++) {
                printWriter.print(random.nextFloat());
                printWriter.print(";");
                if (random.nextDouble() < 0.0000001) {
                    printWriter.write("a");
                } else {
                    printWriter.print(random.nextFloat());
                }
                printWriter.print(";");
                printWriter.print(random.nextFloat());
                printWriter.println();
            }
            printWriter.flush();
        }
    }

    private static ByteArrayOutputStream AlsBlobLaden() throws IOException {
        ByteArrayOutputStream BuArrayOutputStream = new ByteArrayOutputStream();
        try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("csv.txt"))) {
            int b;
            while ((b = bufferedInputStream.read()) != -1) {
                BuArrayOutputStream.write(b);
            }
        }
        return BuArrayOutputStream;
    }

    private static ByteArrayInputStream BuArrayOutputStreamToBuArrayInputStream(ByteArrayOutputStream BuArrayOutputStream) {
        return new ByteArrayInputStream(BuArrayOutputStream.toByteArray());
    }

    private static void NUR_AUSRUFEZEICHENAUSRUFEZEICHENAUSRUFEZEICHEN_Parsen(ByteArrayInputStream byteArrayInputStream) throws IOException {
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(byteArrayInputStream))) {
            String l;
            while ((l = bufferedReader.readLine()) != null) {
                String[] split = l.split(";");
                float f_eins = Float.parseFloat(split[0]);
                float f_zwei = -1;
                try {
                    f_zwei = Float.parseFloat(split[1]);
                } catch (NumberFormatException numberFormatException) {
                    System.out.println("Es gab eine NFE: " + numberFormatException.getMessage());
                }
                float f_drei = Float.parseFloat(split[2]);
                SpaeterWichtigesObjekt spaeterWichtigesObjekt = new SpaeterWichtigesObjekt(f_eins, f_zwei, f_drei);
            }
        }
    }
}

class SpaeterWichtigesObjekt {

    float f_eins;
    float f_zwei;
    float f_drei;

    SpaeterWichtigesObjekt(float f_eins, float f_zwei, float f_drei) {
        this.f_eins = f_eins;
        this.f_zwei = f_zwei;
        this.f_drei = f_drei;

        if (Math.random() < 0.0000001) {
            System.out.println("f_drei = " + f_drei);
        }
    }

}
Runtime.getRuntime().totalMemory() = 202
Runtime.getRuntime().maxMemory() = 7282
Runtime.getRuntime().freeMemory() = 199

Runtime.getRuntime().totalMemory() = 4227
Runtime.getRuntime().maxMemory() = 7282
Runtime.getRuntime().freeMemory() = 234

Es gab eine NFE: For input string: "a"
Es gab eine NFE: For input string: "a"
f_drei = 0.2...
Es gab eine NFE: For input string: "a"
Es gab eine NFE: For input string: "a"
f_drei = 0.7...
Es gab eine NFE: For input string: "a"
f_drei = 0.9...
Es gab eine NFE: For input string: "a"
Es gab eine NFE: For input string: "a"
f_drei = 0.3...
Runtime.getRuntime().totalMemory() = 4092
Runtime.getRuntime().maxMemory() = 7282
Runtime.getRuntime().freeMemory() = 1915

Schreiben: 52179
Lesen:     40797
Parsen:    43969

(Die CSV-Datei ist ungefähr 2 GB.)

Das ist jetzt der Beweis für:

  1. Das “Parsen” dauert länger als das Lesen,
  2. die CPU “ist langsamer” als das “Drive”,
  3. SpaeterWichtigesObjekt anlegen und Weiteres ist langsam (in Java)!

Edit: Probiert es gern’ selber aus. Es wird benötigt: -Xmx8g und 2 GB Speicherplatz und 'ne SSD (muss aber nicht unbedingt, da das Lesen usw. hier nicht das Problem darstellt.)

Edit 2: Schritt 2 (Lesen) ist sogar doch recht umfangreich, denn beinhaltet ja sogar 3 Schritte (OutputStream, InputStream und new byte[]…).