Code-Snippet

Diese Berechnung sieht mir übrigens kommutativ aus

float d = (float) Math.sqrt((sys1.x - sys2.x) * (sys1.x - sys2.x) + (sys1.y - sys2.y) * (sys1.y - sys2.y) + (sys1.z -     sys2.z) * (sys1.z - sys2.z));
            if (d >= A_MAGIC_VALUE_ONE && d <= A_MAGIC_VALUE_TWO) {
                als.add(new Sys[]{sys1, sys2});
            }

wenn sys1, sys2 in als landet, dann landet auch sys2, sys1 in als und umgekehrt. lediglich wenn sys1 === sys2 ist, dann landet es nur einmal drinnen und die auch nur, wenn die untere Schranke kleiner gleich 0 ist, weil d dann ja 0 ist.

Das kann man sich dann wie folgt zu Nutze machen, so dass man nur das untere Dreick berechnet und statt O(n*n) nur noch O(n * n * 1/2) hat. Spart also schonmal die Hälfte der Zeit.

Sys[] syssArr = syss.values().toArray(new Sys[0]);
for(int i = 0; i < syssArr.length; i++) {
  for(int j = i; j < syssArr.length; j++) {// bei j = i starten für unteres Dreieck
    Sys sys1 = syssArr**;
    Sys sys2 = syssArr[j];
    float d = ...
    if(d >= ... && d <= ...) {
      als.add(new Sys[]{sys1, sys2});
      if(i != j) { // Wenn nicht in der Diagonale, dann Werte aus oberem Dreieck hinzufügen.
        als.add(new Sys[]{sys2, sys1});
      }
    }
  }
}

Allerdings unterscheidet sich dann die Reihenfolge von als. Wenn als also auch ein Set sein könnte, dann wäre das kein Problem.

1 „Gefällt mir“

Danke für deine Antworten. :wink: Ich setz mich morgen ran.

Diese LinkedHashMap könnte „doppelt so langsam“ sein wie eine „normale“ HashMap — sogar String als hashs könnte es verlangsamen.

Bis morgen.

Ok, Menge der Daten hat sich sogar vergrößert.
Es gibt nicht mehr 36t Systeme, sondern ~ 15 Mio. Systeme.
Diese sind in einer fast 2GiB großen .CSV Datei gespeichert…
Das Lesen aller Daten dauert etwa 1:30 , über das Speichern noch keine Gedanken gemacht…

Eckdaten und neue Struktur:

    private static final ArrayList<Sys> syss1 = new ArrayList<>();
    // ^ and v contains same Refs to Syss
    private static final HashMap<Long, Sys> syss2 = new HashMap<>();

    private static final LinkedHashMap<Long, Sta> stas = new LinkedHashMap<>();
    private static final LinkedHashMap<Long, Itm> itms = new LinkedHashMap<>();
    private static final LinkedHashMap<Long, LinkedHashMap<Long, Lis>> buys = new LinkedHashMap<>(); // staid and lisid
    private static final LinkedHashMap<Long, LinkedHashMap<Long, Lis>> sells = new LinkedHashMap<>(); // staid and lisid
run:
syss1.size() = 15029926
syss2.size() = 15029926
stas.size() = 67081
itms.size() = 328
buys.size() = 46848
bc = 2262764
sells.size() = 28020
sc = 1385310
Runtime.getRuntime().totalMemory() = 4841275392
Runtime.getRuntime().maxMemory() = 5726797824
Runtime.getRuntime().freeMemory() = 1200631568
BUILD SUCCESSFUL (total time: 1 minute 30 seconds)

Ich musste der VM 6g zusichern, CPU teilweise bis 50 % (also zwei Kerne voll). Fängt aber der GC an, verlangsamt sich alles und CPU bis 100 %…

Danke für den Tipp mit dem unterem Dreieck (es wären wirklich doppelte gewesen)… Das mach ich später.

Frage gleich vorweg: Sollte man syss, stas, itms sowei buys and sells >Serialisieren<, oder würd das bei der Menge nix sparen?

Jetzt bin ich wieder an dieser Stelle:

        for (int i = 0; i < syss1.size(); i++) {
            Sys sys1 = syss1.get(i); // its an ArrayList!:) No iterator needed
            for (int j = i + 1; j < syss1.size(); j++) { // its an Triangle!:)
                Sys sys2 = syss1.get(j);
                float d = (sys1.x - sys2.x) * (sys1.x - sys2.x) + (sys1.y - sys2.y) * (sys1.y - sys2.y) + (sys1.z - sys2.z) * (sys1.z - sys2.z); // float Calculations...
                if (d >= 784 && d <= 1024) {
                    // now go on with some Filtering...
                    // with sys1 and sys2

                }
            }
        }

Und jetzt ist die Frage nach der Performance oder dann nicht besser DBS(?):

Ich würd’ das auf 3GB schätzen, und es schreibt jemand 50GB+ sei auch nicht so schwer.

Suggestions?

Du solltest wirklich mal schauen wo es hakt. Nachmessen.

Haben die beiden Vorschläge, die ich gebracht habe, wirklich etwas gebracht? Wie lange dauert es denn mit den ursprünglichen Daten.

Zudem waren dies ja nur rudimentäre Verbesserungen. Wenn es wirklich darum geht etwas schneller zu machen, dann muss man von Zeit zu Zeit auch etwas Nachdenken, bevor man programmiert.

Letztendlich wird die Entfernung von einem Element, zu allen anderen Elementen berechnet und dann geschaut, ob sich dieses Element in einem bestimmten Umstreifen (von Umkreis abgeleitet) befindet.

Hierfür alle Entfernungen zu berechnen ist bei ausreichender Datenmenge nicht förderlich, da O(n^2).

Wenn man zum Beispiel, ein Zweidimensionales Problem nimmt, versteht man es einfacher. Nehmen wir also ein Schachspiel (40cm * 40cm, 8x8, ein Quadrat hat eine Seitenlänge von 5 cm) und man möchte alle Figuren um den Turm, der auf A1 steht finden, die mindestens 5 und Maximal 10 cm davon entfernt sind.

Dann kommen hierfür maximal nur bestimmte Felder in Frage auf denen eine Figur stehen kann. A2, B2, B1, sowie A3, B3, C3, C2, C1
Man geht quasi hin und zieht zwei Kreise um den Turm auf A1 mit 5 und 10 cm und sieht, dass diese Felder darin stehen.
A + 5cm horizontal ist B
A + 10cm horizontal ist C
1 + 5cm vertikal ist 2
1 + 10cm vertikal ist 3
-5 und -10 ist natürlich Out-of-Bounds bei einem Schachfeld.

Jetzt schaut man eben auf diese Felder und sieht welche Figuren darauf stehen. Und nur für diese Figuren berechnet man die Entfernung zum Turm auf A1.
Es macht ja keinen Sinn die Entfernung zu einer Figur zu berechnen, die auf H8 steht, weil zu weit entfernt. Man braucht aber die Zuordnung der Figuren zu den Feldern. Allerdings nur einmalig zu machen.

Genau das gleiche kann man auch im n-dimensionalen Raum machen. Man unterteilt den Raum in Quader.
Dann Teilt man seine Objekte auf diese Quader auf. Nun berechnet man welche dieser Quader Objekte enthalten, die potentiell Interessant sind und berechnet nur für diese die Entfernung. Alle anderen kann man getrost ignorieren.

Bei entsprechender Aufteilung der Daten kann dies eine Signifikante Reduktion der Rechenoperationen nach sich ziehen und damit eben entsprechend Zeit sparen.

Zu dem Schluss bin ich vorhin auch gekommen.

O((n^2+n)/2) = O(n^2) = O((15029926^2+15029926)/2) = O(15029926^2) , Das ist zu viel.

Hatte es 50 Min. laufen lassen, mit 100 % auf einem Kern - und kein Ergebnis. Wollte einfach nur die „Treffer“ zählen (also die Anzahl der Punkte die in einer bestimmten Entfernung zueinander).

~ 226 Billion (deutscher Sprachgebrauch) berechnungen sind zu viel - auch nur die Hälfte davon.

15029926^2 / 333.000.000.000 IPS (MIPS Zahl des i7) = Wären aber eigentlich 12 Minuten.


Bevor ich das mit der Einteilung in Quader versuche, möchte ich noch Multithreading…

Bei 4 Kernen… Wie müsste ich die Bereiche von i wählen? (Einfach 15029926 / 4 ?)

Bei 4 Kernen ist das maximum an Gewinn bei 75%. Selbst dies ist schwer zu erreichen.

Wurzel aus 1024, der Oberen Grenze ist 32.
Wenn die Quader 32 x 32 x 32 gross sind. Dann kann man das ja recht gut aufteilen.
Ist ein Objekt mit den Koordinaten 1;1;1 ausgestattet, dann ist es im Raum der von 0;0;0 bis 32;32;32 aufgespannt wird.
Alle in Frage kommenden Punkte sind in dem selben Raum oder den Räumen drumherum. Also zwischen
(-32:-32:-32) und (64;64;64) Also Kantenlänge 96 x 96 x 96. Insgesamt 27 Räume mit der Kantenlänge 32

Geht man davon aus, dass da nicht alle Werte drin sind und man es leicht bestimmen kann, welche Werte hierfür in Frage kommen, dann braucht man nur noch sehr wenige Werte berechnen, die tatsächlich darin liegen.

Das kann man dann auch recht einfach auf mehrere Kerne verteilen, indem man Tasks macht, welche man in eine Queue einreiht, bei denen der eine Punkt und ein kleinerer Raum übergeben wird, der durchsucht wird.

Wenn es statt 60 Min. nur 15 Min. dauern würd’, wäre das schon gut.

Aber i-wie hab ich gerade eine Denkblockade. Wie muss i gewählt werden? Wenn n=1000 sei: solve ((1000^2+1000)/2) = ((x^2+x)/2)/4 for x - Wolfram|Alpha ? :confused:


Der erste Kern 0 bis n*0,125, der zweite Kern n*0,125 bis n*0,25, der dritte Kern n*0,25 bis n*0,50, der vierte Kern n*0,50 bis n*1,00 … Ist das richtig? Wie berechnet man es?


Stimmt das?:

Kern 1: 0.0015220700152207 , 0.15220700152207 % , from 0 , to 22876
Kern 2: 0.0243531202435312 , 2.43531202435312 % , from 22877 , to 388901
Kern 3: 0.1948249619482496 , 19.48249619482496 % , from 388902 , to 3317105
Kern 4: 0.7792998477929984 , 77.92998477929984 % , from 3317106 , to 15029926

Kern 1 bekäme nur 0.15 %?

Moin,
hab das heute Nacht 3 Std. und 50 Min. getestet, ich versteh’ das gerad’ gar nicht:

class Worker implements Runnable {
    int from, to;
    ArrayList<Sys> syss1;
    long count = 0;

    Worker(int index, ArrayList<Sys> syss1) {
        double d = 1;
        double[] ds = new double[5];
        for (int i = 0; i < 4; i++) { // diese Berechnung ist etwas umständlich gemacht
            d /= 2;
            ds[4 - i] = d / 0.9375;
        }
        for (int i = 1; i < 5; i++) {
            ds** = ds[i - 1] + ds**;
        }
        from = (int) (ds[index - 1] * syss1.size()) + (index == 1 ? 0 : 1);
        to = (int) (ds[index - 0] * syss1.size());
        System.out.println("from = " + from);
        System.out.println("to = " + to);
        System.out.println((to - from) * 100.0 / syss1.size());

        this.syss1 = syss1;
    }

    @Override
    public void run() {
        System.out.println(System.currentTimeMillis() + " Start " + this + " from " + from + " to " + to + ".");
        Sys sys1, sys2;
        for (int i = from; i < to; i++) {
            sys1 = syss1.get(i); // its an ArrayList!:) No iterator needed
            for (int j = i + 1; j < syss1.size(); j++) { // its an Triangle!:)
                sys2 = syss1.get(j);
                float d = (sys1.x - sys2.x) * (sys1.x - sys2.x) + (sys1.y - sys2.y) * (sys1.y - sys2.y) + (sys1.z - sys2.z) * (sys1.z - sys2.z); // float Calculations...
                if (d >= 784 && d <= 1024) {
                    // now go on with some Filtering...
                    // with sys1 and sys2

                    count++;
                }
            }
        }
        System.out.println(System.currentTimeMillis() + " End " + this + " from " + from + " to " + to + ".");
    }
}
from = 0
to = 1001995
6.666666223107153
from = 1001996
to = 3005985
13.3333257928216
from = 3005986
to = 7013965
26.666658239035907
from = 7013966
to = 15029926
53.33332978485723

Alle 4 Kerne 100 %, kein Kern fertig gewesen.

O(n^2) = O(n^2/2) (Dreieck…) = O((n^2/2)/4) (4 Kerne) = 15029926^2/2/4…

Wenn ich von 300.000 MIPS (und das ist von 2014 ! ) ausgehe, dann käme ich ohne alle Optimierungen nur auf 12 Min.

Was hab ich falschgemacht, und/oder warum so langsam?


… Wäre in so etwas die GraKa schneller?

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
	at java.util.TimSort.mergeLo(TimSort.java:777)
	....
        System.out.println("minMaxAndAvg = " + Arrays.toString(minMaxAndAvg));

        Collections.sort(syss1, (Sys o1, Sys o2) -> Math.round(o1.x - o2.x));
        System.out.println("Sorted syss1");
syss1.size() = 15029926
....
minMaxAndAvg = [-42213.8125, -17162.34375, -16899.75, 40503.8125, 6794.40625, 65630.15625, -2232.6065445904164, -112.33403373043183, 12045.59441804365]
....

:face_with_thermometer: ?

Hab es jetzt in 8 Quader eingeteilt und suche nur innerhalb der Quader.

    public void run() {
        System.out.println(System.currentTimeMillis() + " Start " + this + " from " + from + " to " + to + ".");
        Sys sys1, sys2;
        for (int i = from; i < to; i++) {
            sys1 = syss1.get(i);
            for (int j = i + 1; j < to; j++) {
                sys2 = syss1.get(j);
                float d = (sys1.x - sys2.x) * (sys1.x - sys2.x) + (sys1.y - sys2.y) * (sys1.y - sys2.y) + (sys1.z - sys2.z) * (sys1.z - sys2.z);
                if (d >= 784 && d <= 1024) {

                    count++;

                    if ((int) ((i - from) * 1000 / (syss1.size() * 0.125)) > pro) {
                        pro = (int) ((i - from) * 1000 / (syss1.size() * 0.125));
                        System.out.println(this + " , pro = " + pro);
                    }
                }
            }
        }
        System.out.println(System.currentTimeMillis() + " End " + this + " from " + from + " to " + to + ".");
    }

gestartet um 12:25 Uhr :clock1230: , bis jetzt zeigt er mir 0.1 % an (immerhin, vorhin nicht mal 0.1 %).

noch Verbesserungen?

So… Wieder verworfen! Hab die Eingabe von 15 Mio. auf 0,5 Mio. begrenzt, und suche mitten in der Punktwolke.

Es ist dabei immer noch O(n^2/2), das ist für 0,5 Mio. verschmerzbar:

class Worker implements Runnable {

    final int from, to, n;
    final ArrayList<Sys> syss1;
    volatile long count = 0;
    int pro = 0;

    Worker(int n, int index, ArrayList<Sys> syss1) {
        double[] ds = new double[n];
        double sum = 0;
        for (int i = 1; i <= n; i++) {
            ds[n - i] = Math.pow(0.5, i);
            sum += Math.pow(0.5, i);
        }
        System.out.println("sum = " + sum);
        System.out.println(Arrays.toString(ds));
        for (int i = 1; i < n; i++) {
            ds** = ds[i - 1] + ds**;
        }
        for (int i = 0; i < n; i++) {
            ds** /= sum;
        }
        System.out.println(Arrays.toString(ds));
        from = index == 1 ? 0 : (int) (ds[index - 2] * syss1.size()) + 1;
        to = (int) (ds[index - 1] * syss1.size());

        /*
        double d2 = 1.0 / n * (index - 1);
        from = (int) (d2 * syss1.size()) + (index == 1 ? 0 : 1);
        to = (int) ((1.0 / n + d2) * syss1.size());
         */
        System.out.println("from = " + from);
        System.out.println("to = " + to);
        System.out.println((to - from) * 100.0 / syss1.size());

        this.syss1 = syss1;
        this.n = n;
    }

    @Override
    public void run() {
        System.out.println(System.currentTimeMillis() + " Start " + this + " from " + from + " to " + to + ".");
        Sys sys1, sys2;
        for (int i = from; i < to; i++) {
            sys1 = syss1.get(i);
            for (int j = i + 1; j < syss1.size(); j++) { // beachte: Läuft bis n
                sys2 = syss1.get(j);
                float d = (sys1.x - sys2.x) * (sys1.x - sys2.x) + (sys1.y - sys2.y) * (sys1.y - sys2.y) + (sys1.z - sys2.z) * (sys1.z - sys2.z);
                if (d >= 784 && d <= 1024) {
                    // now go on with some Filtering...
                    // with sys1 and sys2

                    count++;

                    if ((int) ((i - from) * 100 / (to - from)) > pro) {
                        pro = (int) ((i - from) * 100 / (to - from));
                        System.out.println(this + " , pro = " + pro);
                    }
                }
            }
        }
        System.out.println(System.currentTimeMillis() + " End " + this + " from " + from + " to " + to + ".");
    }
}

Problem: Die Threads laufen unterschiedlich lange!!

Runtime.getRuntime().totalMemory() = 2705850368
Runtime.getRuntime().maxMemory() = 5726797824
Runtime.getRuntime().freeMemory() = 770249688
sum = 0.99609375
[0.00390625, 0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5]
[0.00392156862745098, 0.011764705882352941, 0.027450980392156862, 0.058823529411764705, 0.12156862745098039, 0.24705882352941178, 0.4980392156862745, 1.0]
from = 0
to = 2406
0.39209742789954094
sum = 0.99609375
[0.00390625, 0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5]
[0.00392156862745098, 0.011764705882352941, 0.027450980392156862, 0.058823529411764705, 0.12156862745098039, 0.24705882352941178, 0.4980392156862745, 1.0]
from = 2407
to = 7219
0.7841948557990819
sum = 0.99609375
[0.00390625, 0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5]
[0.00392156862745098, 0.011764705882352941, 0.027450980392156862, 0.058823529411764705, 0.12156862745098039, 0.24705882352941178, 0.4980392156862745, 1.0]
from = 7220
to = 16844
1.5683897115981638
sum = 0.99609375
[0.00390625, 0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5]
[0.00392156862745098, 0.011764705882352941, 0.027450980392156862, 0.058823529411764705, 0.12156862745098039, 0.24705882352941178, 0.4980392156862745, 1.0]
from = 16845
to = 36095
3.13710535622035
sum = 0.99609375
[0.00390625, 0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5]
[0.00392156862745098, 0.011764705882352941, 0.027450980392156862, 0.058823529411764705, 0.12156862745098039, 0.24705882352941178, 0.4980392156862745, 1.0]
from = 36096
to = 74597
6.274373678952712
sum = 0.99609375
[0.00390625, 0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5]
[0.00392156862745098, 0.011764705882352941, 0.027450980392156862, 0.058823529411764705, 0.12156862745098039, 0.24705882352941178, 0.4980392156862745, 1.0]
from = 74598
to = 151600
12.548747357905423
sum = 0.99609375
[0.00390625, 0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5]
[0.00392156862745098, 0.011764705882352941, 0.027450980392156862, 0.058823529411764705, 0.12156862745098039, 0.24705882352941178, 0.4980392156862745, 1.0]
from = 151601
to = 305608
25.097983615346884
sum = 0.99609375
[0.00390625, 0.0078125, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5]
[0.00392156862745098, 0.011764705882352941, 0.027450980392156862, 0.058823529411764705, 0.12156862745098039, 0.24705882352941178, 0.4980392156862745, 1.0]
from = 305609
to = 613623
50.19596723069377

Wie berechnet man, “von wo bis wo” ein Thread/Runnable laufen muss? wenn das gesamte Schleife (n^2+n)/2 ist?

@ionutbaiu : Eine Frage hätte ich noch.

Bis jetzt werden alle Strecken berechnet, die <= 1024 Distanz sind…


Es gibt ja das TSP… Wenn man jetzt aber immer zwei dieser Strecken “zusammennimmt”, die max. Distanz zwischen zwei Punkten ist begrenzt, der min. Profit zwischen zwei Punkten (also auf einer Strecke) ist begrenzt, der Profit soll maximiert werden… (Der Profit ist nicht abhängig von der Länge der Strecke) Und es soll ein Loop werden, und es gibt immer genau 4 Punkte…

Wonach muss ich suchen? Wie heißt das Verfahren? Ich finde zum Beispiel: “Airline Route Profitability”… (Edit: Lässt sich das adaptieren oder transferieren?)


O von…: n^2 * 4 * 2 , also n^2 , richtig?

Skizze:

Anmerkung: Zwei Strecken können parallel sein (f und g), zwei Strecken können identisch sein (i und h), zwei Strecken können “nahe beieinander sein” (j und k), zwei Strecken können “sich kreuzen” , …


Es gibt nur genau 2 Möglichkeiten, zwei Strecken zu einem Loop zu verbinden - oder?


( (*): Eine Strecke A B hat Profit1 von A nach B, und Profit2 von B nach A. )

            final int maxdis = ...
			
            for (int i = 0; i < RESULTS.size(); i++) {
                Result r1 = RESULTS.get(i);
                Sys sys1 = syss2.get(r1.sysid1);
                Sys sys2 = syss2.get(r1.sysid2);
                for (int j = i + 1; j < RESULTS.size(); j++) {
                    Result r2 = RESULTS.get(j);
                    Sys sys3 = syss2.get(r2.sysid1);
                    Sys sys4 = syss2.get(r2.sysid2);

                    float d13 = (sys1.x - sys3.x) * (sys1.x - sys3.x) + (sys1.y - sys3.y) * (sys1.y - sys3.y) + (sys1.z - sys3.z) * (sys1.z - sys3.z);
                    float d14 = (sys1.x - sys4.x) * (sys1.x - sys4.x) + (sys1.y - sys4.y) * (sys1.y - sys4.y) + (sys1.z - sys4.z) * (sys1.z - sys4.z);

                    float d23 = (sys2.x - sys3.x) * (sys2.x - sys3.x) + (sys2.y - sys3.y) * (sys2.y - sys3.y) + (sys2.z - sys3.z) * (sys2.z - sys3.z);
                    float d24 = (sys2.x - sys4.x) * (sys2.x - sys4.x) + (sys2.y - sys4.y) * (sys2.y - sys4.y) + (sys2.z - sys4.z) * (sys2.z - sys4.z);

                    // 1 3 4 2 (1) , vorwärts und rückwärts
                    if (d13 <= maxdis && d24 <= maxdis) {
                        // cw 1-3 4-2
						
                        // ccw 2-4 3-1
                        
                    }
                    // 1 4 3 2 (1) , vorwärts und rückwärts
                    if (d14 <= maxdis && d23 <= maxdis) {
                        // cw 1-4 3-2
                        
                        // ccw 2-3 4-1
                        
                    }
                }
            }

„Er“ findet auch zum Beispiel A -> B -> A -> B -> A.

In RESULTS2 liegen Loops mit 4 Systemen. :thinking:

Konnte das lösen, siehe:

if (sys1.id != sys3.id && sys1.id != sys4.id && sys2.id != sys3.id && sys2.id != sys4.id) {

Dadurch, dass die „Rundreise“ nun von 2 auf 4 Systeme erhöht wurde, steigt der Profit um satte 3 % :thinking:

Aber man bereist nicht immer denselben „Ort“, das ist der Vorteil

Okay, Thema done :slight_smile:

Wieder etwas neues… Sorry, falls ich das Thema zweckentfremde…

Ich hab jetzt gelesen, dass der EDT nicht threadsicher ist!

Folgendes Schnipsel steht in einer Methode:

        jta.append(msg);
        jta.append("\n");

msg ist ein String, jta ist ein JTextArea, append fügt etwas hinzu, (vertical) Autoscroll ist auf der jta aktiviert…

Ich hab 16 Threads und insgesamt ca. 100*16=1.600 Ausgaben/Methodenaufrufe pro, sagen wir, Minute.

Nun kann es passieren, das ein Newline verschluckt wird - oder ein msg - oder beides? Also ein Newline wird hin und wieder verschluckt.

FRAGE: Muss ich die Methode synchronisieren?

Nein.

Danke für Deine antwort. Es ist jetzt klar…

Und bis bald. :slight_smile: