Optimierung durch Threads

Highchiller

Bekanntes Mitglied
Hallo Leute,

in der Uni arbeiten wir grad an verschiedensten Projekten. Es geht weitestgehend um Visualisierungen, in meinem Fall um Wellenfunktionen. Wobei wir damit direkt zu meinem Problem kommen.

Damit ich noch nebenbei weiter meine Oberfläche nutzen kann, starte ich einen extra Thread in dem meine Berechnungen ausgeführt werden.
Java:
@Override
public void faceDragStart(FaceDragEvent e) {
	/* Hier passiert nicht viel, nur der Thread wird aufgerufen */
	Thread t1 = new Anim( startPos );
	t1.start();
}

Das eigentlich interessante geschieht natürlich in Anim:
Java:
@Override
public void run(){			
	double t = 0, h = 0;
	
	while ( t < 2 ){
		deformGeo.refresh();
		
		for (int index = 0; index < numOfVerts; index++){
			double[] pos = deformGeo.getCoordinates( index );
				
			/* Hier liegt das Problemchen */
			h = wave.height(pos[0], pos[1], t);
			deformGeo.translateVertex(index, h);
		}
		deformGeo.update();
				
		t += 0.01;
	}
}

Das Problem ist, dass die Funktion wave.height(double x, double y, double t) ziemlich aufwendig ist.
Nun kam mir die Idee vielleicht schon einiges vorweg berechnen zu lassen in einem neuerem Thread. Allerdings könnte es dann passieren, dass der zweite Thread Anim auf den der h berechnet warten müsste.

Das wahre Problem aber ist, ich kenn einiges der Theorie hinter Threads aber ich konnt sie nie wirklich anwenden.
Wie könnte ich das an dieser Stelle realisieren? Zum Beispiel das ich einen extra Thread rechnen lasse und ein anderer stets nur die Ergebnisse nutzt.
Nur.... wie geht das? :D Und vor allem, würde das überhaupt nutzen tragen?

Ich hoffe ihr könnt mir helfen. Vielen Dank schon mal im voraus und liebe Grüße
Highchiller
 

Marco13

Top Contributor
Die Anforderungen werden nicht ganz klar, aber es klingt, als könnte man die Berechnung der Höhe mit einem ThreadPool von mehreren Threads machen lassen, während der gepostete nur zeichnet. Ob und wann er dann auf Ergebnisse warten soll oder muß ist nicht klar.
 
S

Spacerat

Gast
Erinnert mich nicht zuletzt wegen einer Variablenbezeichnung irgendwie an solche Berechnungen, die man anstellt, wenn man die Verformung der Oberfläche einer Flüssigkeit berechnen will, wenn da eine Masse drauf fällt (konzentrische Kreise).
Allerdings würde ich mich dann fragen, was an der Berechnung der Höhen so aufwendig sein soll. Es würde genügen, diese Wellenform pro Zeitabschnitt einmal zu Berechnen und dann die Werte mit Distanz und Richtungsvektoren auf die Oberfläche projeziert. Klappt auch wunderbar bei mehreren, sich überschneidenden Wellen, nur das man dann deren zusammentreffende Höhen addiert und durch die Anzahl der Wellen mit Amplitude != 0 teilt, aber selbst das ist nicht viel aufwendiger.
 

Marco13

Top Contributor
Allerdings würde ich mich dann fragen, was an der Berechnung der Höhen so aufwendig sein soll.

Wenn es von einer Sache NIE genug geben wird, dann davon: Rechenleistung. (Und Speicher). Sowas wie Partikelbasierte Flüssigkeitssimulation kann beliebig aufwändig sein (notfalls modelliert man einzelne Wassermoleküle :smoke: )
 
S

Spacerat

Gast
Wenn es von einer Sache NIE genug geben wird, dann davon: Rechenleistung. (Und Speicher). Sowas wie Partikelbasierte Flüssigkeitssimulation kann beliebig aufwändig sein (notfalls modelliert man einzelne Wassermoleküle :smoke: )
:lol: Jau... Okay... @TO: Evtl. fehlt hier noch die Info ob es ich um ein hoch wissenschaftliches Projekt oder um gängige Praxis handelt.
 

ww_slack

Mitglied
Wenn Du mehrere wave.height(...); Berechnungen parallelsieren möchtest kannst Du für jede einen weiteren Thread aufmachen. Das Zauberwort zum Warten lautet join():

Ob es so wirklich schneller wird hängt an der benutzen Maschine und daran, ob wave.height(...); nicht vielleicht selbst Multithreading verwendet.. in dem Fall wäre der Effekt wohl null bis negativ..


Java:
@Override
public void run(){          
    double t = 0, h = 0;
    
    while ( t < 2 ){
        deformGeo.refresh();

        List<Thread> meineThreads = new ArrayList<Thread>(numOfVerts);

        for (int index = 0; index < numOfVerts; index++){                           
            meineThreads.add(runSingleCalculation(index, t));
        }

        for (Thread one :meineThreads ) {
             one.join();
        }

        deformGeo.update();
                
        t += 0.01;
    }
}

private Thread runSingleCalculation(int index, double t) {

            /* Hier implementierst Du den Start eines weiteren Threads und gibst den Thread zurück:

            double[] pos = deformGeo.getCoordinates( index );
            h = wave.height(pos[0], pos[1], t);
            deformGeo.translateVertex(index, h);
            */

}
 

Highchiller

Bekanntes Mitglied
Ja Theorie ist das Eine, Praxis das Andere.
Es geht ja auch eher darum, dass die Berechnung aufwendig ist und ich das durch Threads optimieren möchte. Ob das jetz tatsächlich aufwendig ist oder nicht, tut eigentlich nichts zur Sache :p zumindest im Moment nicht.

Vielen Dank slack.
Ich werd erst Nachts dazu kommen, dass auszuprobieren. Meld mich dann noch mal :)
 

Highchiller

Bekanntes Mitglied
Hmm ok das hat leider nicht funktioniert.
Ist es hier jetzt nich auch eher enorm ineffizient für jedes h nene neuen thread zu starten?

Das Ding ist halt, die Methode "update()" braucht lange, und daran kann nichts rumgeschraubt oder verändert werden. Daher dacht ich mir ein Thread könnte doch schon mal los legen. Während der eigentliche thread halt immer nach dem updaten mal nach älteren ergebnissen fragt. Sozusagen.

Könnt ihr damit was anfangen oder wär das blödsinn was ich hier rede?
 

Marco13

Top Contributor
Wah nein, nicht für jedes einen Thread! Am einfachsten einen Executors.fixedThreadPool mit vielleicht 4 oder 8 Threads erstellen, und dem mit executeAll die Aufgaben (d.h. die Höhenberechnungen) zuschanzen (executeAll wartet auch automatisch...)
 

Highchiller

Bekanntes Mitglied
Ah ja sowas hab ich mir schon eher vorgestellt :D
Könntest du mir vielleicht ein paar codeschnipsel zu werfen wie das aussehen könnte? Wie gesagt theorie ist das eine, aber ich hab mit executers und threadpools noch nie gearbeitet.
Eventuell wären sogar Tasks angemessen, da es ja tatsächlich nur um strikte mathematische Berechnungen geht.... aber von Tasks hab ich noch viel weniger Ahnung ~.~
 
S

Spacerat

Gast
Also wenn "wave.height()" nicht mal das Problem ist, sondern "update()", könnte man eben genau nur diese Methode als Thread auslagern. Aber evtl. hilft's ja schon, wenn man die nach ausserhalb der "while"-Schleife legt, weil dann wird sie nur 1 statt 200 Mal aufgerufen (selbiges gilt für "refresh()").
Okay, ich weiss nicht genau was "deformGeo" ist (vermutlich 'ne Heightmap). Was passiert eigentlich bei "refresh()" und was bei "update()"? Kann es sein, dass "refresh()" zwischen einem Back- und einem Visiblebuffer hin und herschaltet und "update()" dann die Daten des eben beschriebenen Back- in den Visiblebuffer kopiert (oder etwas ähnliches)? Wenn dem so ist, wäre "update()" ohnehin an der falschen Stelle bzw. im falschen Thread.
 

Marco13

Top Contributor
Könntest du mir vielleicht ein paar codeschnipsel zu werfen wie das aussehen könnte?

In http://www.java-forum.org/java-basics-anfaenger-themen/127689-laufzeit-verkuerzen.html#post830791 hatte ich mit der methode 'doitMT' mal ein paar Zeilen gepostet, die sehr generisch "irgendeine Berechnung" (in diesem Fall: 'doit' ;) ) in Teile zerlegen und parallel ausführen kann. In der 'doit' würdest du dann eben die Höhenwerte zwischen den indizes "min" und "max" berechnen (und insgesamt würden damit alle zwischen 0 und numberOfVerts berechnet)
 

Highchiller

Bekanntes Mitglied
Also das ganze funktioniert so... es basiert alles auf Java3D (nur als spezielle software entwickelt von der TUB, heißt JReality)

Im Moment habe ich einen "Torus" (im Prinzip nen Donut) der sich wie Wasser verhalten soll. Der Torus besteht aus, sagen wir 80*80 Punkten (damit die Oberfläche möglichst "smooth" ist).
In der for-schleife gehen wir nun jeden Knoten durch, berechnen seine Höhe und verschieben diesen entlang seiner Normalen. Noch wird aber nichts gezeichnet, daher geht das auch "relativ" schnell. Bis auf die Tatsache das wir jedes mal ne komplizierte Rechnung durchführen um die Höhe zu errechnen (Mathematik Studium, Schwerpunkt liegt natürlich auf Mathematik).
Update() ist dann der eigentliche Kern der Methode. Sie zeichnet/visualisiert/realisiert dann wirklich die Anzeige und zeichnet alle neuen (also verschobenen) Vertices. Würde ich jetzt update() auslagern (außerhalb der while-schleife) wäre also überhaupt nix zu sehen :p
Refresh setzt einfach alles auf default zurück, damit ich nicht jedes mal neu nach oben verschoben wird sondern stets aus Höhe 0 + h gerechnet wird.

So... Also update() ist langsam und die ganze for-schleife ist natürlich auch langsam.
Theoretisch sollte update() so schnell aufgerufen werden, dass man ne flüssige Bewegung erkennt. Je mehr Vertices, desto langsamer, logisch ;)

@ Marco, ah ok... das schau ich mir doch mal an :)
Hab Dank.

@ Spacerat, und? Fällt dir mit den Erläuterungen noch was ein? :)
Auch dir, hab dank
 
S

Spacerat

Gast
Fast wie ich es mir gedacht habe (Okay, du has die Beschreibung der "refresh()"-Methode vergessen, aber egal).

Wie sieht's grad' aus:
Torus wird berechnet, Torus wird gezeichnet.

Wie es werden soll:
Ein Torus wird gezeichnet, während der nächste schon berechnet wird.

Daraus folgt, dass es zumindest schon mal 2 Torusse geben müsste, dessen Zugriff man in den jeweiligen Threads sperrt. Am Anfang eines Zyklus werden die Torusse ausgetauscht. Der Renderthread (der Teil in welchen die "update()"-Methode gehört) kann nun einen zeichnen während der Logikthread den anderen berechnet. "refresh()" und "update()" müssen dann auch nicht mehr so oft aufgerufen werden, sondern wie gesagt pro Renderzyklus einmal.
Wenn ich Zeit hätte, würd' ich auch 'nen KSKB erstellen.
 

Highchiller

Bekanntes Mitglied
Refresh setzt einfach alles auf default zurück, damit ich nicht jedes mal neu nach oben verschoben wird sondern stets aus Höhe 0 + h gerechnet wird.
:bae:
Die refresh() Methode hab ich jetzt eh entfernt. Hab das etwas anders gelöst, tut aber nichts zur Sache.

Ja genau so hab ich mir das auch eher vorgestellt. Nur könnte es ja (wie auch immer) passieren, dass der Logikthread noch gar nicht fertig gerechnet hat und update() warten muss bis das fertig ist. Andersrum kann es aber auch passieren, dass update() zu langsam ist, dann müsste ich einfach all meine berechneten Ergebnisse speichern damit update() dann darauf zurückgreifen kann.

Nur eben genau da liegt mein Problemchen. Ich weiß nicht wie ich dem update-Thread sage, nu mach mal solangs geht, wenn nich wart halt kurz und leg dann wieder los.
Ich will gar kein ganzess KSKB. Mir würden halt theoretische Codeschnipsel schon reichen :/

Da würde es sich sicher auch anbieten gleich den Threadpool zu nutzen, wie von Marco13 beschrieben? :rtfm:
 
S

Spacerat

Gast
:oops: Wer lesen kann ist klar im Vorteil. Naja... die Zeile war zu klein, ist wohl keine Entschuldigung. :lol: Aber gut, dass du sie rausgenommen hast, resetten muss man so ein Objekt auf keinen Fall, wenn man beim Berechnen der Wellenform eh' eine Variable mit 0 initialisiert und dann im Torus die Werte einfach setzt.

Das Problemchen mit dem Warten, hatte ich mit "sperren" gemeint. So etwas nennt sich Monitor und einen solchen bekommt man mit dem Schlüsselwort synchronized. Ich bin, was Threads angeht, leider auch nicht ganz uptodate (kenne die Concurrency-API nur vom Hörensagen) und würde es deswegen mit "wait()"- und "notify()"-Konstrukten lösen. Sicher bietet diese Concurrency-API aber auch dafür etwas an.
 
Zuletzt bearbeitet von einem Moderator:

Highchiller

Bekanntes Mitglied
Hmm mit wait() hät ich doch aber nichts gewonnen. Wenn der Logikthread ständig sagt, update() warte mal bis ich fertig bin, dann kann update() ja auch erst aufgerufen werden wenn wirklich alles durch exerziert wurde. Das wär ja Blödsinn. Wenn ich ihm aber nach jedem neuen berechnen sage warte bis ich mit dieser schleife durch bin, dann läuft das programm doch genau wie jetzt. Erst die for-schleife, dann update(), for-schleife, update() und so weiter...
Oder seh ich da was falsch?
 
S

Spacerat

Gast
Hmm mit wait() hät ich doch aber nichts gewonnen. Wenn der Logikthread ständig sagt, update() warte mal bis ich fertig bin, dann kann update() ja auch erst aufgerufen werden wenn wirklich alles durch exerziert wurde. Das wär ja Blödsinn. Wenn ich ihm aber nach jedem neuen berechnen sage warte bis ich mit dieser schleife durch bin, dann läuft das programm doch genau wie jetzt. Erst die for-schleife, dann update(), for-schleife, update() und so weiter...
Oder seh ich da was falsch?
Das siehst du falsch... gleich nach wait() werden die Buffer (Torusse) ausgetauscht und beide Threads gehen gemeinsam in den nächsten Zyklus... der eine berechnet den nächsten Schritt, der andere zeichnet den zuvor berechneten. Wie gesagt, es werden zwei Torusse benötigt. Diese hält man in einem Array, so benötigt man zum Umschalten nur noch ein "count++; count %= 2". Der Renderthread benutzt dann "Torus[count]" und der Logikthread "Torus[1 - count]". Wenn ein Thread schneller ist, muss er halt auf den anderen warten. Natürlich dauert das Berechnen und Zeichnen insgesammt eben solange wie zuvor, jedoch läuft das Ganze ja parallel ab (siehe Grafik).
 

Anhänge

  • MultiThreading.png
    MultiThreading.png
    6 KB · Aufrufe: 31
Zuletzt bearbeitet von einem Moderator:

Highchiller

Bekanntes Mitglied
Dumm gelaufen ~.~
Es wurde nicht schneller... Hier mal mein momentaner Code:
Java:
// Hier der Haupt-Thread (der update() aufruft)
@Override
public void run() {
	inProgress = true;
	
	double t = 0;
	double timeStep = 0.01, timeEnd = 2;
	
	int steps = (int)(timeEnd/timeStep)+1;
	saveArray = new double[steps][numOfVerts][3];
	
	synchronized (this){ // um den thread zu warten zu lassen bzw. wieder zu wecken
		
		CalculationThread compute = new CalculationThread( this, timeStep, steps );
		compute.start();
		
		try { this.wait(); } 
		catch (InterruptedException e1) {}
		
		for ( int index = 0; index < steps; index++ ){				
			if ( tmpCounter > index ){ // counter zählt bis wohin wir gerechnet haben
				deformGeo.setVertexCoordinates( saveArray[index] );
				deformGeo.update();
			} else { // falls wir noch nicht soweit sind, index zurücksetzen und warten
				try { 
					index--; 
					this.wait();
				} catch (InterruptedException e) { System.out.println("Wait failed"); }	
			}
		}
		
	}
	
	inProgress = false;
}

// Hier die Klasse für die Berechnungen der Höhe aller Knoten
private class CalculationThread extends Thread{
	private AnimationThread masterThread;
	private double timeSteps;
	private int steps;
	
	private CalculationThread( AnimationThread masterThread, double timeStep, int steps ){
		this.masterThread = masterThread;
		this.timeSteps = timeStep;
		this.steps = steps;
		tmpCounter = 0;
	}
	
	@Override
	public void run(){
		for( int step = 0; step < steps; step++ ){
			double t = step*timeSteps;
			saveArray[step] = deformGeo.defaultVertices.clone();
			
			for (int index = 0; index < numOfVerts; index++){
				double[] pos = deformGeo.getCoordinates( index );
				double h = wave.height(pos[0], pos[1], t);
				saveArray[step][index] = deformGeo.translateVertexTEST(index, h);
			}
			
			synchronized ( masterThread ){
				tmpCounter++;
				masterThread.notify(); // update-thread wieder aufwecken
			}
		}
		
	}
	
}

Schade, da brauch die Berechnung der Höhe aller Vertices wohl doch deutlich länger als update().
Jetzt würde sich halt wieder anbieten die Höhe doch via Threadpool zu berechnen oder was meint ihr?
Noch Ideen? :)
Wie gesagt, Tasks sollen angeblich deutlich fixer und effizienter sein nur... da hab ich echt mal gar kein Plan von :/
 
Zuletzt bearbeitet:

andiv

Bekanntes Mitglied
Ich hab mir jetzt deinen Code nicht angeschaut. Ich kann dir aber das Buch "Java Concurrency in Practice" und darin insbesondere die Abschnitte über "Producer-Consumer-Probleme" empfehlen. Das hat mir beim Verständnis von Threads und Executors u.s.w. sehr geholfen.

Hast du eigentlich schonmal mit einem Profiler (z.B. JVisualVM) gemessen, an welchen Stellen der Flaschenhals liegt?
 

Highchiller

Bekanntes Mitglied
Zeile 58, wave.getHeight ist das Problem ;)
Da es um eine approximative Näherung an eine Wellengleichung im 2 Dimensionalen geht, dauert das erstaunlich lang.
Ich schätze ich nutz dafür nen Pool wie von Marco13 oben empfohlen. Die Hauptarbeit dafür hab ich ja bereits getan. Und mehr ist dann wohl wirklich nur noch im mathematischen Hintergrund zu holen ;)

Habt dank :)
 

Marco13

Top Contributor
Beim Draufschauen sehe ich da jetzt erstmal nur EINEN Thread, hab's aber nicht gelesen...

EDIT: Oh, das war wohl noch VOR dem letzten Beitrag...
 
Zuletzt bearbeitet:

Highchiller

Bekanntes Mitglied
Sooo... Also die Laufzeit lässt immer noch zu wünschen übrig aber mehr ist nicht drin. Wenn man sich vorstellt das für jeden Punkt (bei ungefähr 100*100 Knoten) die Höhe approximativ durch 2 ineinander von 1 bis 15 laufende for-schleifen berechnet wird, ist das schon sehr akzeptabel :D

Hier der Code (gekürzt)
Java:
@Override
public void run() { // die haupt-run methode
	/* blabla vorweg, variablen definieren und co */
	synchronized (this){
		CalculationThread compute = new CalculationThread( this, timeStep, steps );
		compute.start(); // startet einen thread für die berechnung aller translationen zu jedem zeitpunkt
		
		for ( int index = 0; index < steps; index++ ){			
			if ( tmpCounter > index ){ // wenn die berechnung schon durchgeführt wurde, updaten
				deformGeo.update( saveArray[index] ); // saveArray enthält translatierte vectoren
				
				try { this.sleep(40); } // falls die calculations zu schnell werden
				catch (InterruptedException e) { e.printStackTrace(); }
			} else { // falls man noch nicht so weit ist, erst mal warten, dann den index noch mal prüfen
				try { 
					index--;
					this.wait();
				} catch (InterruptedException e){}	
			} // if-else
		} // for
	} // synchronized
	
	deformGeo.refresh(); // auf ausgansposition zurücksetzen
	inProgress = false;
}

private class CalculationThread extends Thread{
	/* menge blabla, konstruktor und co */

	@Override
	public void run(){
		ForkJoinPool transPool = new ForkJoinPool(); // erstellt task-pool
		
		for( int step = 0; step < steps; step++ ){ // für jeden zeitschritt den task-pool rechnen lassen
			double t = step*timeSteps;
			transPool.invoke( new TranslateTask( saveArray[step], 0, numOfVerts-1, t ) );
			
			synchronized ( masterThread ){
				tmpCounter++; 
				masterThread.notify(); // update() aufwecken
			}
		}
		
	}	
} // CalculationThread

private class TranslateTask extends RecursiveAction{
	/*auch wieder blabla vorweg */

	@Override
	protected void compute() {			
		if ( end - start < 100 ){ // direkt berechnen wenns weniger als 100 knoten sind
			for (int index = start; index <= end; index++){
				double[] pos = deformGeo.getCoordinates( index );
				double h = wave.height(pos[0], pos[1], time);
				verts[index] = deformGeo.translateVertex(index, h);
			}
			return;
		} /* wenn nicht dann teilen wir die aufgaben auf mehrere tasks auf */

		int middle = (start+end)/2;
		TranslateTask transFirst = new TranslateTask( verts, start, middle, time );
		transFirst.fork();
		
		TranslateTask transSecond = new TranslateTask( verts, middle+1, end, time );
		transSecond.compute();
		transFirst.join();
	}
}

Eine Frage an dem Punkt vielleicht noch. Ich habs aus der neuen version von "Java, Mehr als eine Insel".
Da stand halt auf dem ersten task rufen wir ".fork()" auf.
Auf dem zweiten dann ".compute()" (das is klar)
und DANACH noch mal ".join()" auf den ersten. Das letzte ist mir unklar. Bzw. ist mir fork() nicht ganz klar.
Was würde passieren würde ich .fork() weglassen? Bzw. was wenn ich .join() weglassen würde?

Vielen Dank und eine gute Nacht wünsch ich :)
Highchiller
 
S

Spacerat

Gast
fork - englisch bedeutet Gabel. Damit ist jetzt nicht die Gabel, mit der man isst (konsumiert) gemeint, sondern eher eine Weggabelung. Programmtechnisch teilt sich dort der Programmfluss in 2 parallel laufende Zweige. Ich frag' mich nur, was an dieser Stelle ein "join()" zu suchen hat, weil bei einem solchen ja auf einen Thread gewartet wird, bis er beendet wurde. Der langsamere Thread soll sich aber nicht beenden, sondern er soll von vorne beginnen und den schnelleren darüber informieren, dass es weiter gehen kann. Da müsste ich nun auch die fragen, die sich mit Concurrency besser auskennen: Werden bei ForkJoin etwa laufend neue Threads erzeugt?
Ich hätte das ganz pragmatisch so gelöst:
Java:
public class RenderAndCalc {
	private Torus[] buffers = new Torus[] { new Torus(), new Torus() };
	private Thread renderer, calculator;
	private int count;

	RenderAndCalc() {
		renderer = new Renderer();
		calculator = new Calculator();
	}

	void start() {
		renderer.start();
		calculator.start();
	}

	public static void main(String[] args) {
		RenderAndCalc rnc = new RenderAndCalc();
		rnc.start();
	}

	class Renderer extends Thread {
		@Override
		public void run() {
			synchronized (this) {
				try {
					wait();
				} catch (InterruptedException e) {
					interrupt();
				}
			}
			synchronized (buffers[count]) {
				// wenn der torus gerade noch berechnet wird, geht's hier nicht
				// weiter
				buffers[count].update();
			}
		}
	}

	class Calculator extends Thread {
		@Override
		public void run() {
			synchronized (buffers[1 - count]) {
				// wenn der torus gerade noch gezeichnet wird, geht's hier nicht
				// weiter
				buffers[1 - count].calc();
			}
			count++;
			count %= 2;
			synchronized (renderer) {
				renderer.notify();
			}
		}
	}
}

class Torus {
	private Wave wave;
	private int numVerts;

	void update() {
		// TODO Auto-generated method stub
	}

	void calc() {
		double t = 0, h = 0;
		while (t < 2) {
			for (int index = 0; index < numVerts; index++) {
				double[] pos = getCoordinates(index);
				h = wave.height(pos[0], pos[1], t);
				translateVertex(index, h);
			}
			t += 0.01;
		}
	}

	/**
	 * @param index  
	 * @param h 
	 */
	private void translateVertex(int index, double h) {
		// TODO Auto-generated method stub
	}

	/**
	 * @param index  
	 */
	private double[] getCoordinates(int index) {
		// TODO Auto-generated method stub
		return null;
	}
}

class Wave {
	/**
	 * @param d 
	 * @param e  
	 * @param t 
	 */
	public double height(double d, double e, double t) {
		// TODO Auto-generated method stub
		return 0;
	}
}
Die erstellten Klassen Torus und Wave sind natürlich Dummies und können durch die existierenden ausgetauscht werden, bis auf eine Einschränkung: die Methode "<Torus>.calc()" müsste entweder so beim Original erstellt werden oder ihr Inhalt (inkl. numVerts und wave) im Thread dorthin kopiert werden, wo sie aufgerufen wird und die Referenz zum Torus gesetzt werden.
 

Marco13

Top Contributor
Hmja, das ForkJoin hat mich auch irritiert. Es ist ja von Anfang an bekannt, was gemacht werden muss, und das Problem kann sehr leicht in gleichgroße Teile zerlegt werden (die auch gleich viel Zeit benötigen). Einen Anlass, das durch ForkJoin zu machen, sehe ich nicht, aber ob es mit einem "pragmatischeren" Ansatz schneller oder langsamer wäre, ist schwer zu sagen...
 

Highchiller

Bekanntes Mitglied
Also die Geometry zu kopieren wär nicht so praktisch. Das wird aber nicht ersichtlich wenn man das ganze Programm nicht kennt.
Aber das mit dem synchronized von spacerat hat mich vorran gebracht. Ich wusste nämlich nicht wie man das verwendet. Jetzt ist mirs klar :)

Zum neuen Ansatz mit ForkJoin. Er ist schon massiv schneller. Ich nutz jetz auch 100% der CPU und erreich damit schon einiges. Mit Threads würd ich das vermutlich auch schaffen aber es wurde immer wieder erwähnt das eine derartige Aufgabenzerteilung mit ForkJoin einfach effizienter wäre. Zumal die Verteilung auf Threads und nebenläufigkeit vom Pool anscheinend selbst gesteuert wird.

Und zu guter letzt zu dem join() am ende.
Ich habs mal weggenommen und er hat etliche Vertices nicht verschoben. Ich tippe darauf, dass ForkJoin den letzten join() befehl benötigt um die beiden laufenden Tasks quasi zu verknüpfen. Sie sollen ja parallel arbeiten also so effizient wie möglich gleichzeitig alles berechnen.
Ohne join() würde task1 aber task2 gar nicht kennen.
Das ist allerdings nur ne Vermutung, richtig drinne steck ich in der Materie bei weitem nicht :)

Wie dem auch sei, es funktioniert. Vielen Dank
Hab ma wieder ne Menge gelernt.
 
S

Spacerat

Gast
Ui... das Kopieren der GeoDaten ist aber essentiell, für die Funktion meiner Version, denn sie dienen als Monitore für die jeweiligen Threads. Kopiert werden sie ja auch nicht, es werden blos zwei gleiche Geometrien erstellt und immer wieder verwendet, bei anderen Methoden dürfte es nicht anders sein. Der Hintergrund ist einfach der, dass keiner der beiden Threads auf die Geometrie des jeweils anderen zugreifen darf, sonst gibt's Kaudawelsch.
Nehmen wir mal an, beide Threads würden die selbe Geometrie verwenden und der Calculator wäre definitiv langsamer. Der Renderer würde dann mit den Daten der Laufenden Runde korrekt anfangen, früher oder später auf alte bzw. anfangs sogar ungültige Daten stossen, weil der Calculator halt noch nicht soweit ist. Das wäre dann Runde für Runde das Gleiche. Darüber hinaus würden auch beide Threads wieder gegeneinander (bzw. hintereinander) laufen, weil eben nur ein Objekt als Monitor dient. BTW.: Ein Monitor kann nur zu einem Thread gehören. Ist der Monitor eines Objekts bereits durch einen anderen Thread belegt, muss der, der drauf Zugreifen will solange warten, bis der andere ihn wieder freigegeben hat.
 

Highchiller

Bekanntes Mitglied
Naja alles was ich momentan mache ist die Koordinaten der Vertices zu kopieren und diese dann zu updaten. Damit ich nicht ausversehen daten verwende die noch gar nicht berechnet wurden hab ich ja einen counter (ziemlich simple idee) eingebaut der mir immer den index des neusten berechneten ergebnisses zurück gibt. damit fang ich ab was ich nutzen darf und was nicht.

Wenn mein updater schon zugreifen will, obwohl der counter noch nicht so weit ist, wird gewartet bis meine calculate ihn wieder weckt. (was nach jedem neuen counter++ geschieht)
Ziemlich simple eigentlich. Speichertechnisch sicherlich verbesserungswürdig aber es funktioniert :)
 
S

Spacerat

Gast
Damit ich nicht ausversehen daten verwende die noch gar nicht berechnet wurden...
Genau dazu ist der 2. Torus da (bedenke, dass sie in ihren Threads gesperrt werden).
Das ist zwar nicht besonders gut für den Speicher, aber um so besser für die Performance und der korrekten Anzeige. Das Ganze wäre so eine Art Doublebuffering. Bei Morphobjekten würde ich mich zu keiner Zeit gegen dieses Verfahren wehren, es sei denn du hast bereits 'nen Shader dafür, der das alles auf der Graka berechnet, aber ich denke mal, dass man auch da 2 Buffer verwenden würde.
Die Daten eines bereits gezeichneten Torus dürften doch eigentlich nicht mehr von belangen sein. Falls doch, dann muss halt ein 3. her, der im Calculator-Thread die aktuellen Berechnungen speichert.
 

Highchiller

Bekanntes Mitglied
Ja stimmt schon, die Idee des doubleBuffers.
Allerdings liegt halt die Geometry in einer SceneGraphComponent. Ne extra SceneGraphComponent erstellen und dann die sichtbarkeit ändern? Da zweifel ich doch. Und die Geometry einer SceneGraphComponent ändern dauert.
Passt jetz schon so :)
 
S

Sym

Gast
Ich würde da ein anderes Modell zu Grunde legen. Wenn es wenig Punkte sind, kann man mit finiten Elementen arbeiten. Oder einfach ein Federmodell. Es ist klar, dass es langsam ist, wenn Du jeden Punkt einzeln berechnest.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Optimierung einer Methode (byte-Geraffel) Allgemeine Java-Themen 2
L Best Practice Auslagerung von Code = Performance Optimierung? Allgemeine Java-Themen 4
F Zeit Optimierung - bzw. ms Optimierung Allgemeine Java-Themen 35
R Optimierung beim Vergleichen von 2 Bildern Allgemeine Java-Themen 23
HarleyDavidson Regex - Optimierung Allgemeine Java-Themen 4
K Optimierung kürzester Weg im Warenlager Allgemeine Java-Themen 8
O Algorithmus Optimierung Allgemeine Java-Themen 3
C Programmflow-Optimierung Allgemeine Java-Themen 7
G Klasse Optimierung Allgemeine Java-Themen 6
N Optimierung einer Berechnung Allgemeine Java-Themen 17
S jdk versus openjdk - Optimierung von Konstanten? Allgemeine Java-Themen 8
P Optimierung (&& ||) deaktivieren / umgehen? Allgemeine Java-Themen 9
G Optimierung StringBuilder Allgemeine Java-Themen 9
S Optimierung vom Laden von Grafiken Allgemeine Java-Themen 4
S Brainstorming --> Optimierung vonn Gefälleplatten Allgemeine Java-Themen 8
D Optimierung beim Casten Allgemeine Java-Themen 4
V Java-Codierungsherausforderung: Navigieren durch die Macken der Datumsmanipulation Allgemeine Java-Themen 2
H Dienst durch ssh forwarding absichern? Allgemeine Java-Themen 15
M Klasse durch Klassen Aufteilung verbessern, aber wo? Allgemeine Java-Themen 1
M Kein Scanner Fehler durch falsche EIngabe Allgemeine Java-Themen 4
P Karate API Test läuft nicht durch . initializationError Allgemeine Java-Themen 21
Y Wie bekomme ich durch getImage an das Image heran? Allgemeine Java-Themen 1
T Meine Frage lautet wie ich 2 CSV Dateien miteinander in Java verbinde und Spalten die zueinander gehören durch den gleichen Key zusammen ausgebe? Allgemeine Java-Themen 5
W Java Telegram Bot - Eingabe durch User Allgemeine Java-Themen 2
Drachenbauer Wie kann ich das Wort "concrete" in einem String durch ein anderes Wort ersetzen lassen? Allgemeine Java-Themen 5
I Buchstabe durch seinen Nachfolger ersetzen Allgemeine Java-Themen 29
M Jdeps-Error durch multi-release Allgemeine Java-Themen 6
J Reflection Aufruf: .class durch .dll ersetzen Allgemeine Java-Themen 4
mrbig2017 Threads wait wird nicht durch notify beendet! Allgemeine Java-Themen 3
C OpenCl Setup und durch JavaCode ansteuern Allgemeine Java-Themen 17
J Erste Schritte Datenspeicherung durch Java Allgemeine Java-Themen 6
M Hässliche Schrift auf Graphics durch deriveFont Allgemeine Java-Themen 0
R Variable durch mehrere Methoden ändern und nutzen Allgemeine Java-Themen 17
Aruetiise Interface Position durch JButton ermitteln Allgemeine Java-Themen 5
K Jar/DLL Abhängigkeiten durch User angeben lassen Allgemeine Java-Themen 6
4 Swing Durch klicken auf Button Labels einem Panel hinzufügen Allgemeine Java-Themen 4
R Rückgabe eines Arrays durch Funktion Allgemeine Java-Themen 9
T AWT AWT-EventQueue-0 Null_Pointer_Exception durch Variable Allgemeine Java-Themen 12
RalleYTN Problem bei Schleife die durch einen 2D raum iterieren soll Allgemeine Java-Themen 1
C Durch klicken von Button in GUI wird leeres Fenster geöffnet und nicht mein Spiel "Memory" Allgemeine Java-Themen 13
T Quadrieren einer Zahl nur durch Addition Allgemeine Java-Themen 5
L Vererbung If-Else ersetzen durch was? Allgemeine Java-Themen 20
K OOP OOP Gui Spiel + Vererbungen Probleme durch Nichtwissen!! Allgemeine Java-Themen 1
I CountDown wird durch JOptionPane unterbrochen Allgemeine Java-Themen 11
F JTable mit Zellen die sich durch andere Eingaben füllen Allgemeine Java-Themen 1
B Counting Sort (Sortieren durch Zählen) Allgemeine Java-Themen 13
Z Durch Bäume iterieren Allgemeine Java-Themen 3
M Unterbrechnung durch Echtzeitbefehle? Allgemeine Java-Themen 4
G Suchweg durch Binärbaum speichern Allgemeine Java-Themen 4
L Label- & Textfelderzeugung durch Button Allgemeine Java-Themen 1
S RandomAccessFile durch bytearrayinputstream ersetzen Allgemeine Java-Themen 4
H Java Leistungssteigerung durch Code Anpassung Allgemeine Java-Themen 5
S JTable: Model durch ein anderes ersetzen Allgemeine Java-Themen 2
P Variablen Auf durch for-Schleife generierte JComboBox zugreifen Allgemeine Java-Themen 3
T Code durch eigenes Frame pausieren (ähnlich JDialog) Allgemeine Java-Themen 4
F Live Ticker durch Screenshots Allgemeine Java-Themen 22
C Hex Zeichen ersetzen durch leer Zeichen Allgemeine Java-Themen 5
M Verschlüsselung von Text und Files durch RSA (Encoding Problem) Allgemeine Java-Themen 7
N Algorithmus durch Workflow Allgemeine Java-Themen 7
R Windows-Firewall lässt Java nicht durch Allgemeine Java-Themen 17
E Oracle kann durch 0 teilen !?! Allgemeine Java-Themen 7
E NetBeans Vector durch ArrayList ersetzen Allgemeine Java-Themen 4
J Java Datei durch Java Datei öffnen Allgemeine Java-Themen 16
M Arraynamen durch Variable festlegen lassen Allgemeine Java-Themen 5
R Implementierung eines Interface durch 2 verschiedene Klassen Allgemeine Java-Themen 6
S Bildaufbau durch Servlet -> Exception Allgemeine Java-Themen 11
F Slash durch Systembezogenen Fileseparator ersetzen Allgemeine Java-Themen 18
P JFormattedTextField für durch Semikolon getrennte Integer-Werte gesucht / Regulärer Ausdruck Allgemeine Java-Themen 3
M Eclipse drei slashs durch zwei ersetzen? Allgemeine Java-Themen 3
D Updaten von Klassen durch jar.exe zerstört diese. Update durch WinRAR gelingt! Allgemeine Java-Themen 2
A SWT Ausgabetext Shellscript durch Java Allgemeine Java-Themen 8
Ark Array durch Interface ersetzen Allgemeine Java-Themen 7
K Objekt einer konkreten Implementierung eines Interfaces durch übergebenen String Allgemeine Java-Themen 2
fastjack Hardwareinformationen durch Java auslesen Allgemeine Java-Themen 7
S durch Code steppen Allgemeine Java-Themen 7
E Durch System.in.read() blockierten Thread stoppen Allgemeine Java-Themen 10
M eigene Klasse durch Composition mit java.io.File erweitern Allgemeine Java-Themen 3
C Markierung durch Maus lesen Allgemeine Java-Themen 9
T Synchronisation von Listen bei Zugriffen durch mehrere Prozesse Allgemeine Java-Themen 15
N Scanner läuft nicht durch Allgemeine Java-Themen 2
F kamera auslösen durch Programm Allgemeine Java-Themen 17
M Maus durch JavaProgramm bewegen Allgemeine Java-Themen 2
Dissi Itext - Anordnung von Elementen durch PDF Writer Allgemeine Java-Themen 2
N Casten durch generic vermeiden ?? Allgemeine Java-Themen 10
H Performancegewinn durch Mehrfachobjeknutzung Allgemeine Java-Themen 3
N Fehler abfang läuft doppelt durch Allgemeine Java-Themen 2
H Performance Vorteil durch Wechsel der JVM? Allgemeine Java-Themen 6
G String.replaceall - mehrere Zeichen durch eines ersetzen Allgemeine Java-Themen 5
S Testen einer Anwendung durch klicken von Koordinaten Allgemeine Java-Themen 7
N int[] eindeutig durch eine Zahl repräsentieren Allgemeine Java-Themen 12
GilbertGrape Durch JDK debuggen Allgemeine Java-Themen 2
Q Objekte durch Reflection erzeugen Allgemeine Java-Themen 18
Chris81T Performance Problem durch mehrfaches Starten eines JAVA Prog Allgemeine Java-Themen 8
G Schleife durch Button beenden Allgemeine Java-Themen 6
royale Breitendurchlauf / Dijkstra durch Graph, vereinfacht Allgemeine Java-Themen 3
Hawkes Beschädigte Tarballs durch JavaTar Allgemeine Java-Themen 2
X Status Anzeige-durch Thread? Allgemeine Java-Themen 15
4 ich steige einfach nicht durch Allgemeine Java-Themen 5
P Thread Demonstrationr eist durch die Zeit Allgemeine Java-Themen 4
D erstellung einer seitenlangen xml durch ireport Allgemeine Java-Themen 3

Ähnliche Java Themen

Neue Themen


Oben