PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Java, Threadgroup und Thread-Lebensdauer



BlueJay
30-01-2011, 16:19
Hallo Leute,

da ist so ein Programmteil, welches eine Thread-Flut erzeugt. Diese kicken je eine Funktion mit je einem bestimmten Parameter an und sollen dann von der Bildfläche verschwinden.

Soweit tun sie das auch, aber nach getaner Arbeit sind sie ziemlich zählebig.
Bei der Erzeugung von 400-1000 Threads verschwinden sie noch ziemlich schnell aus der ThreadGroup (>50Stück /100ms), aber bei 5000 verdrücken sich nur laaaangsam (3-8/100ms).
Laaangsam heisst, sie lümmeln gut doppelt so lange herum, wie sie für die Arbeit brauchten. Ich brauche den Speicher aber für was anderes!

Der System-Monitor vom Betriebssystem zeigt in etwa dieselbe Bevölkerung an wie die Überwachung der Gruppe.

Es bringt nichts, die Dinger auf null zu setzen, beim Abfragen der ThreadGroup ist da immer noch Hochbetrieb drin.

Es bringt nichts, zusätzlich die GC aufzurufen.

Thread.stop hat ebenfalls keinen Einfluß auf das Benehmen.

Thread.destroy ist nicht vorhanden.

Code:


int i,i0=0,blocksize=100;
while(i0<symax)
{ try
{ for (i=0; i<blocksize; i++)
{ final int ii=i+i0;
if (ii<symax)
{ Thread t=new Thread(tg,"zeile"+ii) { @Override public void run() { mach_zeile(ii); }; };
t.start();
}
}
i0=i0+blocksize;
}
catch(OutOfMemoryError e) { break; }
}

und

synchronized void mach_zeile(int zz)
{ double douzi=pot1min+zz*dzy;
double douci=pot2min+zz*dcy;
for (int ix=0; ix<sxmax; ix++)
{ gb.setColor(mycolor.get_color(ju.get_slope(kin1min +ix*dzx,douzi,kin2min+ix*dcx,douci)));
gb.drawRect(ix,zz,1,1);
Thread.yield(); // sonst blockiert GUI
}
}

Hat jemand noch ein paar Tricks?

Gruß,
Ulrike

anda_skoa
30-01-2011, 17:08
Wenn du nicht gerade auf einem Cluster oder etwas ähnlichem arbeitest, ist eine so große Anzahl von Threads ohnehin nicht sehr sinnvoll.

Einerseits weil das Erzeugen von Threads eine relativ kostspielige Operation ist und andererseits weil der Scheduler des Betriebsystems dann mehr zu tun hat, um zu entscheiden, wer auf welcher CPU dran kommt.

Wenn du sehr viele ähnliche und unabhängige Aufgaben hast, ist wahrscheinlich das Arbeiten mit einem Threadpool effiezienter.

http://konstantin.filtschew.de/blog/2009/06/14/mit-threadpoolexecutor-arbeit-unter-java-effizient-parallelisieren/
http://download.oracle.com/javase/tutorial/essential/concurrency/pools.html

Ciao,
_

BlueJay
30-01-2011, 19:36
Cluster? JA! BITTE! :D

Da habe ich also die Arbeiten so zerhackt, dass man die Zeilengenerierung schön an Threads weiterreichen kann. Das gab einen irren Geschwindigkeitsvorteil.

Nachteil: man muss jedem Thread einen speziellen Parameter mitgeben.
Ich habe zwar herausbekommen, wie das beim Erzeugen geht, aber nicht, wie zwischendurch.

Der Versuch der Wiederverwertung ergab einen java.lang.IllegalThreadStateException.

Aber das Erzeugen und Durchführen von ca 5000 Threads war kein Problem für den Rechner, sondern die Geschichten wieder abzubauen.

Also: einmal sind se tot, ein andermal nicht.

anda_skoa
31-01-2011, 00:00
Datenübergabe ist ansich kein Problem sofern man auf Sachen wie gleichzeitigen Zugriff Rücksicht nimmt. Man darf den Thread nur nicht aus der run() Method rauslassen (weil dann ist er zu Ende).

Wie gesagt hört sich die Aufgabenstellung sehr nach einem Threadpool Use-case an.
D.h. man gibt alle Aufgaben entsprechend parametriert in den Threadpool und überlässt diesem, sie auf seine Threads aufzuteilen.

Ciao,
_

BlueJay
31-01-2011, 12:27
Hi,

Genau das war mein Problem: run war zu Ende, die Threads aber noch da.

Zudem wird wohl, was die Threadmenge angeht, was Falsches erzählt.
Fakt ist, bei nur 8 Threads kann ich mir zeitmäßig die Mühe sparen, das Feld in Thread-Blöcken bearbeiten zu lassen. Der meldet zwar ruckzuck "bin fertig", aber das Bild ist noch im Aufbau, und das Ganze dauert fast so lange wie ohne Threads. Aber möglicherweise ist das prozessorabhängig.

Einen Fehler habe ich gefunden: der Bildaufbau wurde doppelt gestartet. Das ist bei sequentieller Programmierung nicht problematisch gewesen, die function bekam sozusagen "on the fly" die neuen Parameter und Startwerte mit.
Bei der Thread-Variante lagen etliche Zombies herum. Da kam die GC wohl nicht so einfach ran.

Na, mal sehen, was mir noch zum Killen einfällt.
Jedenfalls werde ich mir das mit dem Threadpool auch ansehen.

Gruß,
Ulrike

BlueJay
04-02-2011, 09:30
sory, dass es so lange gedauert hat, mir ist eine grippe dazwischengekommen.


Zu den Threadpools:
Ja, sie kicken schön die Tasks an, geben auch sofort das Kommando an Swing/awt zurück.

Auf den 1.Blick ist die Berechnung genauso schnell wie die der ThreadGroup, aber auch sie lassen sich nicht so einfach ausbremsen! Bei (versehentlichem) mehrfachern Betätigen des Calc-Buttons kommt es so zu einer Thread-Flut bis ummi 6000 einem Memory-Overflow.

Der Vorteil dieser Konstruktion erschließt sich mir noch nicht so richtig, vor allem, weil er bei shutdown oder shutdownNow den Befehl verweigert.

Dabei soll das Konstrukt doch nur alles stehen- und liegenlassen und die Ressourcen freigeben, wenn neue Parameter kommen!

Aber vielleicht kommt der Aha-Effekt ja, wenn ich mal wieder an das 4-Prozessor-System darf :)

Jetziger Code:

// try { my_pool.shutdown(); } catch(RejectedExecutionException e) { System.out.println("er will nicht"); }
int i=0;
while (i<symax)
{ final int ii=i;
try
{ my_pool.execute(
new Thread() { @Override public void run() { mach_zeile(ii); }; }
);
i++;
}
catch(OutOfMemoryError e) { System.out.println("wieder alles dicht!"); break; }
}

Gruß,
Ulrike

ach ja, my_pool ist ein newCachedThreadPool.
Wenn man shutdownNow ans Rennen kriegt, reduzieren sich zwar die Threads, aber der Speicher wird nicht freigegeben

anda_skoa
04-02-2011, 10:57
So wie ich die Doku von shutdown() interpretiere, hilft dir das in der Tat nicht, weil es trotzdem alle schon angegebenen Aufgaben noch machen wird. Also bleibt nur shutdownNow().

Frage zur Sicherheit: deine Thread Klasse ist kein Thread mehr, nur mehr ein Runnable, korrekt?

Ciao,
_

BlueJay
04-02-2011, 11:08
das ist richtig, so konnte ich mir ein paar mehr "Fehlklicks" leisten, bevor der OutOfMemory zuschlägt. Auch scheint er sich schneller davon "zu erholen".

Und wie gesagt: shutdownNow verhindert die Thread-Explosion, aber nicht das OutOfMemory.

irgendwo weiter oben:

try { my_pool.shutdownNow(); } catch(RejectedExecutionException e) { System.out.println("er will nicht"); }
my_pool=Executors.newCachedThreadPool(); // sonst keine Task-Annahme

BlueJay
04-02-2011, 14:46
Das Ding ist inzwischen auch als Runnabe deklariert ;)

Die ThreadPools sind in punkto Reaktivität der GUI was Feines.

so habe jetzt mal mit FixedThreadPool gearbeitet, einen OutOfMemory konnte ich nicht mehr provozieren, aber die Berechnung ist langsamer geworden bei Drosselung von max. 2800 Tasks auf 1000. Der Speicherverbrauch bleibt unter 1GB, auch bei Calc-Button-Misshandlung.

Und dass der Plakat-Aufbau im ungünstigsten Fall eine Dreiviertelstunde braucht, kann ich verschmerzen.

Gruß,
Ulrike