Große Datenmengen effizient programmieren

Super danke für die Antworten! Ja mrBrown du hast es richtig verstanden und ich habe somit den Streaming Ansatz noch nicht verstanden. Ich werde mich einlesen und wenn ich dann noch fragen habe, werde ich mich wieder melden.
 
BigDecimal, LocalDateTime und Objekte sind für so etwas zu teuer. Anstatt float kannst du auch int nehmen. Du brauchst nicht zu jedem Zeitpunkt alle Daten im Speicher. Schreibe Dir einen Stream dafür. ;)
 
Zum Bleistift so:
Java:
import java.util.Arrays;
import java.util.Iterator;
import java.util.Random;
import java.util.Scanner;
import java.util.StringJoiner;

public class Aktien implements Iterator<int[]> {
	Strings1 s1 = new Strings1();
	String[] s = new String[1000];
	int i = 0;
	int j = 0;

	@Override
	public boolean hasNext() {
		return i < j || s1.hasNext();
	}

	@Override
	public int[] next() {
		if (i == j) {
			i = 0;
			while (i < s.length && s1.hasNext()) {
				s[i++] = s1.next();
			}
			j = i;
			i = 0;
		}
		String[] split = s[i++].split(",");
		int[] l = new int[] { 
				Integer.parseInt(split[0].split(":")[0]), 
				(int) (Float.parseFloat(split[1]) * 100000),
				(int) (Float.parseFloat(split[2]) * 100000), 
				(int) (Float.parseFloat(split[3]) * 100000),
				(int) (Float.parseFloat(split[4]) * 100000) };
		return l;
	}

	public static void main(String[] args) {
		new Aktien().forEachRemaining(l -> System.out.println(Arrays.toString(l)));
	}
}

class Strings1 implements Iterator<String> {
	String s = "2014070110:00:00,1.36921,1.36928,1.36845,1.36898\r\n"
			+ "2014070111:00:00,1.369,1.36972,1.3679,1.36938\r\n" 
			+ "2014070112:00:00,1.3694,1.36966,1.3687,1.36889";
	Scanner sca;

	Strings1() {
		Random r = new Random();
		StringJoiner j = new StringJoiner("\n");
		for (int i = 0; i <= 1111; i++) {
			j.add(2014070110 + i + ":00:00," 
					+ (int) (r.nextFloat() * 100000) / 100000f + ","
					+ (int) (r.nextFloat() * 100000) / 100000f + "," 
					+ (int) (r.nextFloat() * 100000) / 100000f + ","
					+ (int) (r.nextFloat() * 100000) / 100000f );
		}
		s = j.toString();
		sca = new Scanner(s);
	}

	@Override
	public boolean hasNext() {
		return sca.hasNextLine();
	}

	@Override
	public String next() {
		return sca.nextLine();
	}
}

Statt meiner super tollen Klasse Strings1 nimmst Du an der Stelle s[i++] = s1.next(); einfach einen FileReader o.Ä.
 
Java:
public static void main(String[] args) {
        new Aktien().forEachRemaining(l -> System.out.println(Arrays.toString(l)));
    }
Wie soll diese Zeile funktionieren?

Es ist kein Konstruktor deklariert. Selbst wenn ich annehme, dass dennoch ein verwei auf ein Aktion-Ob´jekt übergeben wird, werden zwar hasNext zwei mal implementiert, aber die Methode "forEachRemaining" des gleichen Interfaces aber nicht. Selbst wenn die Variable l vom Typ "int[]" ist, wie komme ich dann zu den Strings?

Das mit dem "Scanner sca" kann ich auch nicht so richtig nachvollziehen.

Wahrscheinlich habe ich zu wenig ahnung von funktionaler Programmierung, aber ich finde das so nicht so richtig nachvollzieh- und wartbar.
 
Wie soll diese Zeile funktionieren?

Es ist kein Konstruktor deklariert. Selbst wenn ich annehme, dass dennoch ein verwei auf ein Aktion-Ob´jekt übergeben wird, werden zwar hasNext zwei mal implementiert, aber die Methode "forEachRemaining" des gleichen Interfaces aber nicht. Selbst wenn die Variable l vom Typ "int[]" ist, wie komme ich dann zu den Strings?
"Es ist kein Konstruktor deklariert"-> default Konstruktor
"werden zwar hasNext zwei mal implementiert" -> nur einmal je Klasse ;)
"aber die Methode "forEachRemaining" des gleichen Interfaces aber nicht" -> ist eine default-Methode, muss also nicht implementiert werden
"Selbst wenn die Variable l vom Typ "int[]" ist," -> ist sie :)
"wie komme ich dann zu den Strings" -> zu welchen String, denen, die ausgegeben werden? Das macht doch genau Arrays.toString

Wahrscheinlich habe ich zu wenig ahnung von funktionaler Programmierung, aber ich finde das so nicht so richtig nachvollzieh- und wartbar.
Das liegt in diesem Fall nicht an Funktionaler Programmierung, sondern an grottenschlechtem Code :)
 
Das sind quasi zwei Puffer, wobei er dann für Berechnungen noch einen dritten Puffer bräuchte.

Es ist kein Konstruktor deklariert
Na und? default

Selbst wenn die Variable l vom Typ "int[]" ist, wie komme ich dann zu den Strings
Im Consumer, nicht Supplier...

Wahrscheinlich habe ich zu wenig ahnung von funktionaler Programmierung
Green check mark ✅ Aber kein Grund zur Besorgnis.
 
Ansonsten, zum Kürzen reduziert auf die Ticks mit 2 Werten statt mit 4:

Java:
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.*;

public class StreamingExample {

    static class Tick {
        //FALLS das wirklich noch ein Problem ist, kann man es ersetzen, zB mit epochSeconds/NanoSecods
        LocalDateTime localDateTime;
        int ask;
        int bid;
        public Tick(final LocalDateTime localDateTime, final int ask, final int bid) {
            this.localDateTime = localDateTime;
            this.ask = ask;
            this.bid = bid;
        }
    }

    //Wie auch immer die Testläufe aussehen
    private static class Testlauf {
        int max = Integer.MIN_VALUE;

        void processTick(Tick tick) {
            max = Math.max(tick.ask, max);
        }
    }

    public static void main(String[] args) {
        Testlauf testlauf = new Testlauf();
        readFile()//Ersetzen mit Files.lines()
                .map(StreamingExample::parseLine)
                .forEach(testlauf::processTick);
        
        System.out.println(testlauf.max);
    }

    static Stream<String> readFile() {
        long epochSeconds = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
        final Random random = new Random();
        return IntStream.range(0, 1111).mapToObj(
                i -> String.format("%s,%.5f,%.5f",
                                   LocalDateTime.ofEpochSecond(epochSeconds + i, 0, ZoneOffset.UTC),
                                   random.nextFloat(),
                                   random.nextFloat())
        );
    }

    static Tick parseLine(String line) {
        String[] columns = line.split(",");
        return new Tick(LocalDateTime.parse(columns[0]),
                        (int) (Float.parseFloat(columns[1]) * 100000),
                        (int) (Float.parseFloat(columns[2]) * 100000));
    }

}
 
statische innere Klassen sind ein Unding,
unnötige Objekte,
hatten wir nicht über LocalDateTime gesprochen?
Note: 6, von mir. :)

Bearbeitung: Achja - das hat natürlich nicht dieselbe Funktionalität.
 
statische innere Klassen sind ein Unding,
Mehrere Klasse pro Datei auch - einigen wir uns darauf, dass es einfach dem Format hier geschuldet ist und man in beiden Fällen mehrere Dateien mit Klassen hätte?

unnötige Objekte,
Da Java keine structs oder ähnliches bietet, muss man wohl Objekte nutzen. Arrays sind kein wirklicher Ersatz für Objekte, vor allem nicht in Hinblick auf Verständlichkeit und Erklärungen, worum es hier ja ging.

hatten wir nicht über LocalDateTime gesprochen?
Nein, nicht wir, nur du. Und weil du LocalDateTime hier nicht als sinnvoll ansieht, steht dort extra ein Kommentar genau dazu.

Bearbeitung: Achja - das hat natürlich nicht dieselbe Funktionalität.
Ich weiß. Allerdings würde ich die gleiche Funktionalität in deinen Augen wohl nur erreichen, wenn es genau der selbe Code ist.

Oder welche großen Unterschiede gibt es in der Funktionalität?
Die Reduzierung auf zwei statt 4 Worte? Ist erwähnt, der Kürze des Programms geschuldet und für die Veranschaulichung völlig unerheblich.
Hinzufügen von Testlauf statt einfach nur Ausgabe aus der Konsole? Dient der Verbesserung der Verständlichkeit im Kontext dieses Threads, wenn es dich stört, denk dir dort einfach einen entsprechendes println.


Falls die relevante Funktionalität, die dein Code zeigen soll, ist, wie man Arrays ausgibt - ja, dann ist das wirklich keine vergleichbare Funktionalität.
 
Da Java keine structs oder ähnliches bietet, muss man wohl Objekte nutzen. Arrays sind kein wirklicher Ersatz für Objekte, vor allem nicht in Hinblick auf Verständlichkeit und Erklärungen, worum es hier ja ging
Es ging hier um große Datenmengen, nicht besonders leserlicher Code. Und structs sind nebenbei unleserlicher als Array.

Wenn du zu derselben Lösung gelangt wärst, wieso spricht du dann von "grottenschlechten Code"? Das ist einfach das was man machen sollte. Das andere ist syntaktischer Zucker.

(So ähnlich wie eine Himbeere - schmeckt gut, hat aber keinen hohen Nährwert.)
 
Es ging hier um große Datenmengen, nicht besonders leserlicher Code. Und structs sind nebenbei unleserlicher als Array.

Wenn du zu derselben Lösung gelangt wärst, wieso spricht du dann von "grottenschlechten Code"? Das ist einfach das was man machen sollte. Das andere ist syntaktischer Zucker.
Okay, ich geh mal einen Schritt auf dich zu.

Es gibt dabei wohl zwei Streitpunkte: Lesbarkeit und Effizienz (und letztere in Geschwindigkeit und Speicher-Verbrauch) - zumindest gehst du auf die beiden in dem Beitrag ein.

Wir können ja mal versuchen, das möglichst objektiv zu vergleichen, (bzw, bei Lesbarkeit so gut es eben geht).


Wenn ich deinen Code richtig verstehe, ist das int-Array der Länge Fünf die Entsprechung für folgende Klasse:

Java:
public class Tick {
    int epochSeconds;
    int open;
    int high;
    int low;
    int close;
    //Boilerplate bewusst weggelassen
}
epochSeconds ist bewusst als int gewählt, damit es dem int-Array entspricht.
Die Beispieldaten des TO haben Millisekunden-Auflösung, man würde also eher einen long oder eben einen andere entsprechenden Datentyp wählen (oder das nur als Millisekunden innerhalb des Tages darstellen, könnte auch möglich sein). Würde aber bei einem Vergleich von Array und Klasse dazu führen, dass man entweder ein long-Array nutzen müsste (wodurch das doppelt so groß wäre, was ein Nachteil fürs Array wäre), oder Array und Klasse hätten unterschiedliche Wertebereiche (was ein unfairer Vergleich wäre, weil nicht mehr fachlich gleich). Deshalb in beiden alles als int.

Aber zurück zur Frage: wäre das eine passende Repräsentation der Daten als Klasse?
 
Ja, wäre es... Aber dann genügt es aus Platzgründen auch ein Array.
Okay, vergleichen wir doch mal den Platzbedarf (Werte sind für 32-Bit*):

* Objekte haben einen 8-Byte Header, dann kommen in diesem Fall fünf mal 4 Byte für die ints hinzu, macht insgesamt 28 Byte.

* Arrays haben eine 12-Byte Header, dazu dann fünf mal 4 Byte für die ints, macht insgesamt 32 Byte.

Beide Werte müssen noch auf ein Vielfaches von 8 aufgerundet werden, macht 32 Byte vs. 32 Byte - Platzgründe sprechen also nicht für ein Array.

Stimmst du mir da zu oder siehst du da Fehler in meiner Rechnung?
Quelle: https://wiki.openjdk.java.net/display/HotSpot/CompressedOops
Fehler gern korrigieren :)

32-Bit:

Der Header besteht aus zwei mal 4-Byte, beim Array zusätzlich 4-Byte für die Array-Länge.

64-Bit:

Objekte und Arrays haben jeweils zwei mal 8-Byte Header, beim Array zusätzlich 4 Byte für die Array-Länge und 4 Byte Padding.
Für Objekte macht 16 Byte für Header und 20 zusätzlich für Felder, mit Padding 40 Byte.
Für Arrays macht das 24 Byte Header, 20 für Daten, mit Pudding also 48 Byte.

64-Bit mit compressed oops:
Der Header besteht aus 8+4 Byte, die Array-Länge rutscht in die 4 Byte, die frei im Vergleich zu 64-Bit sind, das erste Feld des Objekts kann auch in die 4 freien Byte rutschen.
Macht also:
Für Arrays: 16 Byte + 20 für Daten, mit Padding 40 Byte
Für Objekte: 16 Byte (in denen das erste Feld schon enthalten ist) + 16 Byte (für die 4 restlichen Felder), also 32 Byte

Bleibt noch Performance in Bezug auf Zeit und Lesbarkeit als Möglichkeiten für den Vergleich, richtig?

epochSeconds; könnte man ja sogar noch "kürzen", also wenn alle Sekunden-Anzahlen größer gleich eines bestimmten Werts wären...
Kleiner als ein int wird man es aber nicht bekommen, bzw hätte es keinen wirklichen Vorteil (auf Seiten des int-Arrays braucht man sowieso ints, im Objekt könnte man den int bei gleicher Größe durch einen long ersetzen).
Oder wie würdest du das anders als mit einem int darstellen?
 
Ich bin da noch nicht so glücklich. Nehmen wir mal an, die einen Daten sind 2,5 Mega und die anderen 5000 Megabyte. Nehme ich mal weiter an, dass ich beim ersten 50 Byte brauche( rechnet sich leichter), dann sind das 50000 Datensätze, und das andere, da ja auch nu aus 3 int+DateTime bestehend(2*4)+8=16 Byte. Da sind dann ca. 3 Millionen Datensätze. In dem Falle sind es zwar nur 60 Datensätze je Tick(einer je Minute), aber die Beispielzahlen lassen auf bis zu 10000 Datensätze je Tick( 3 je Sekunde) schließen. Theoretisch ist das alles machbar, da die Begrenzung der Größe für Arrays bei 2 Milliarden liegt. Dennoch würde ich die Pufferung nicht an das System abgeben, sondern selbst machen.

Wieso?

Ich bin immer noch eher in der Auffassung verhaftet, dass man nur über Dinge iterieren sollte, die im Speicher sind. Jedenfalls bei Java. Es gibt zwar Streamdeitoren, die würde ich aber nicht typisch für das Java-Konzept sehen.
 
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben