Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

EDV2 - 01 - Parallelprogrammierung1 Parallelprogrammierung mit JAVA.

Ähnliche Präsentationen


Präsentation zum Thema: "EDV2 - 01 - Parallelprogrammierung1 Parallelprogrammierung mit JAVA."—  Präsentation transkript:

1 EDV Parallelprogrammierung1 Parallelprogrammierung mit JAVA

2 EDV Parallelprogrammierung 2 Allgemeiner Hintergrund Computer können heute immer mehrere Programme (quasi-) gleichzeitig ausführen. Viele Computer besitzen mehrere Prozessoren, z.T. mehrere Tausend, z.B. Cray T3E bzw. arbeiten im Cluster mit vielen anderen Rechnern zusammen. Mutiuser-Betrieb: Programme mehrerer Nutzer laufen zur selben Zeit auf dem selben Rechner. Jeder Nutzer bekommt eigene Ressourcen zugeteilt. Multitasking-Betrieb: Jeder Nutzer kann zur selben Zeit mehrere Programme laufen lassen. Jede Task bekommt eigene Ressourcen aus dem Pool des Nutzers und eine vollständig eigene Umgebung. Multithreading-Betrieb: Ein Nutzer-Prozess kann sich in mehrere Threads (Minitasks) aufteilen. Alle Threads nutzen die Ressourcen des Elternprozesses und laufen in dessen Umgebung.

3 EDV Parallelprogrammierung 3 Threads in JAVA Neben ADA ist JAVA die einzige Programmiersprache, die Threads direkt unterstützt. JAVA besitzt Möglichkeiten Threads zu erzeugen, zu starten, zu synchronisieren, zu beenden, zu verwalten sowie zwischen Threads zu kommunizieren

4 EDV Parallelprogrammierung 4 Die Klasse Thread Klassen, die als Thread gestartet werden sollen, müssen von der Klasse Thread abgeleitet werden und die Methode public void run() überschreiben. Ein Thread wird durch Aufruf von name.start() gestartet. Die Methode start ruft anschließend die Methode run auf, die dann die eigentliche Arbeit des Threads erledigt. Das gesamte Programm wird beendet, wenn alle Threads fertig sind Konstruktoren: public Thread() public Thread(String name) erzeugt ein Threadobjekt mit dem Namen name bzw. Thread-nnn

5 EDV Parallelprogrammierung 5 Beispiel1 public class Beispiel1 extends Thread { public void run() //Ausgeben der Zahlen 0,1,2,... { int i = 0; while (true) System.out.println(i++); } } public class Listing1 { public static void main(String[] args) { Beispiel1 t = new Beispiel1(); //Erzeugen des Thread-Objektes t.start(); //Thread starten } }

6 EDV Parallelprogrammierung 6 Nachdem der Thread t gestartet wurde, ist main fertig. Das gesamte Programm wartet auf die Beendigung des Threads. Dieser wird aber nie fertig. Das Programm muss also von außen unterbrochen werden. Es können ein Attribut private boolean cancelled = false; und eine Methode public void cancel() {cancelled=true;} definiert werden. Während run abgearbeitet wird, wird cancelled geprüft und ggf. run beendet. Problem: cancelled muss oft genug abgefragt werden, um eine schnelle Reaktion auf cancel() zu garantieren. cancelled darf aber nicht zu oft abgefragt werden, um die Performance nicht zu stark zu verschlechtern. Es muss garantiert werden, dass die Daten immer konsistent bleiben!

7 EDV Parallelprogrammierung 7 Beispiel2 public class Beispiel2 extends Thread { private boolean cancelled = false; public void cancel() {cancelled=true;} public void run() //Ausgeben der Zahlen 0,1,2,... { int i = 0; while (! cancelled) System.out.println(i++); } } public class Listing2 { public static void main(String[] args) { Beispiel2 t = new Beispiel2(); //Erzeugen des Thread-Objektes t.start(); //Thread starten try{Thread.sleep(1000);} catch (InterruptedException ie){} t.cancel(); } }

8 EDV Parallelprogrammierung 8 interrupt, interrupted, isInterrupted public void interrupt() markiert einen Thread als abgebrochen. public static boolean interrupted() fragt den interrupt-Status des aktuellen Threads ab und setzt ihn anschließend wieder zurück. public boolean isInterrupted() fragt den interrupt-Status ab

9 EDV Parallelprogrammierung 9 Beispiel3 public class Beispiel3 extends Thread { public void run() //Ausgeben der Zahlen 0,1,2,... { int i = 0; while (! isInterrupted()) { System.out.println(i++); try{sleep(100);} catch(InterruptedException ie){interrupt();} } } } public class Listing3 { public static void main(String[] args) { Beispiel3 t = new Beispiel3(); //Erzeugen des Thread-Objektes t.start(); //Thread starten try{Thread.sleep(1000);} catch (InterruptedException ie){} t.interrupt(); } }

10 EDV Parallelprogrammierung 10 Methoden der Klasse Thread public static void sleep(long millis)throws InterruptedException public static void sleep(long millis, int nanos) throws InterruptedException unterbricht den aktuellen Thread für millis/1000+nanos/ Sekunden Falls der Thread in dieser Zeit unterbrochen wird, wird die InterruptedException ausgelöst. public final boolean isAlive() fragt, ob der Thread noch aktiv ist. public final void join() throws InterruptedException join() wartet auf die Beendigung des Threads. Falls der wartende Thread unterbrochen wird, wird die InterruptedException ausgelöst. public final void join(long millis) throws InterruptedException public final void join(long millis, int nanos) throws InterruptedException wartet maximal millis/1000+nanos/ Sekunden

11 EDV Parallelprogrammierung 11 Beispiel4 public class Beispiel4 extends Thread { public void run() //Ausgeben der Zahlen 0,1,2,... { int i = 0; while (i<20) { System.out.println(i++); try{sleep(100);} catch(InterruptedException ie){} } } } public class Listing4 { public static void main(String[] args) { Beispiel4 t = new Beispiel4(); //Erzeugen des Thread-Objektes t.start(); //Thread starten try{ System.out.println("Thread gestartet"); t.join(1000); System.out.println("nach einer Sekunde"); t.join();} catch(InterruptedException ie){} } }

12 EDV Parallelprogrammierung 12 Daemon-Threads Daemon-Threads werden bei der Beendigung des Gesamtprogramms nicht berücksichtigt. Daemon-Threads werden also beendet, wenn alle nicht-Daemon-Threads fertig sind. public final void setDaemon(boolean on) markiert den Thread als Daemon-Thread. setDaemon muss vor dem Start des Threads aufgerufen werden.

13 EDV Parallelprogrammierung 13 Beispiel5 public class Beispiel1 extends Thread { public void run() //Ausgeben der Zahlen 0,1,2,... { int i = 0; while (true) System.out.println(i++); } } public class Listing5 { public static void main(String[] args) { Beispiel1 t = new Beispiel1(); //Erzeugen des Thread-Objektes t.setDaemon(true); //Thread als Daemon markieren t.start(); //Thread starten try{Thread.sleep(100);} catch(InterruptedException ie){} } }

14 EDV Parallelprogrammierung 14 Das Interface Runnable Zuweilen ist es nicht möglich eine Klasse von Thread abzuleiten. Z.B. wenn die Klasse von einer anderen Klasse (z.B. JApplet oder JFrame) abgeleitet werden muss. Dann kann man die Klasse von dem Interface Runnable ableiten und muss dann die Methode run() implementieren. Die Klasse Thread hat dazu weiter Konstruktoren: public Thread(Runnable target) public Thread(Runnable target, String name) Es wird ein Thread-Objekte erzeugt, das von einem Objekt target abgeleitet wird, das das Interface Runnable implementiert.

15 EDV Parallelprogrammierung 15 Beispiel6 public class Beispiel6 implements Runnable { public void run() //Ausgeben der Zahlen 0,1,2,... { int i = 0; while (i<20) { System.out.println(i++); try{Thread.sleep(100);} catch(InterruptedException ie){} } } } public class Listing6 { public static void main(String[] args) { Thread t = new Thread(new Beispiel6()); t.start(); try{ System.out.println("Thread gestartet"); t.join(1000); System.out.println("nach einer Sekunde"); t.join();} catch(InterruptedException ie){} } }

16 EDV Parallelprogrammierung 16 Parallelisierung von QuickSort public class QuickSort { public static void sort(double[] v){ sort(v, 0, v.length-1); } public static void sort(double[] a, int l, int r){ int i = 0; int j = 0; double x = 0; double h = 0; i = l; j = r; x = a[(l+r)/2]; do { while (a[i] < x) { i++; } while (x < a[j]) { j--; } if (i <= j) { h = a[i]; a[i] = a[j]; a[j] = h; i++; j--; } } while (i <= j); if (l < j) sort(a, l, j); if (i < r) sort(a, i, r); } }

17 EDV Parallelprogrammierung 17 Probleme QuickSort ist ein typisches Beispiel, bei dem das ganze Programm erst zu Ende ist, wenn alle Threads ihre Arbeit beendet haben. Auf alle erzeugten Threads muss mit join() gewartet werden. Die Klasse QuickSort muss von Thread abgeleitet werden: public class QuickSort extends Thread Die QuickSort -Methode wurde bisher mit Parametern aufgerufen. Die Methode run ist aber ohne Parameter! Die einzelnen Threads sind Objekte. Man kann nicht mit statischen Methoden arbeiten, sondern muss für jeden Thread ein neues Objekt erzeugen, dessen start -Methode aufgerufen werden muss. Die erforderlichen Parameter können nur beim Konstruktor übergeben werden. Wir müssen entsprechende Konstruktoren schreiben.

18 EDV Parallelprogrammierung 18 private double[] a; private int l; private int r; QuickSort(double[] a, int l, int r){ this.a=a; this.l=l; this.r=r; } QuickSort(double[] a){ this(a, 0, a.length-1); } public void run(){ sort(a, l, r); }

19 EDV Parallelprogrammierung 19 Bisher ist an der eigentlichen Methode sort nichts geändert. Sie kann wie bisher als statische Methode aufgerufen werden. Zusätzlich gibt es nun die Möglichkeit die Sortierung des Feldes a über ein Objekt und dessen Methode run() oder start() zu starten: QuickSort qs = new QuickSort(a); qs.run(); oder qs.start(); Es wird aber noch nicht parallelisiert! Wo kann parallelisiert werden? if (l < j) sort(a, l, j); if (i < r) sort(a, i, r); Wird ersetzt durch: QuickSort tl = null; QuickSort tr = null; if (l < j) {tl = new QuickSort(a,l,j); tl.start();} if (i < r) {tr = new QuickSort(a,i,r); tr.start();} if (tl!=null) tl.join(); if (tr!=null) tr.join();

20 EDV Parallelprogrammierung 20 Problem: Zu viele Threads In dieser Realisierung werden letztendlich ca. doppelt so viele Threads erzeugt, wie das Feld Elemente hat. Fast alle sind sehr klein, sodass der Overhead unverhältnismäßig groß wird. Man muss dafür sorgen, dass nicht zu viele kleine Threads erzeugt werden. Steuerungsmöglichkeit über die Länge des zu sortierenden Abschnittes. Einführung eines Parameters c, der die Mindestlänge eines in einem neuen Thread zu sortierenden Abschnittes beschreibt. Ist die Länge kleiner als c wird kein neuer Thread erzeugt, sondern seriell weitergearbeitet. Der Parameter c ist in die Attributliste, in die Paramterliste der Konstruktoren und der sort-Methode aufzunehmen

21 EDV Parallelprogrammierung 21 private double[] a; private int l; private int r; private int c; QuickSort(double[] a, int l, int r, int c){ this.a=a; this.l=l; this.r=r; this.c=c; } QuickSort(double[] a){ this(a, 0, a.length-1, a.length); } public void run(){ sort(a, l, r, c); }

22 EDV Parallelprogrammierung 22 try { Thread tl=null, tr=null; if ( (l+c

23 EDV Parallelprogrammierung 23 Verwaltung von Threads Threadgroups dienen der Organisation von Threads. Threads können in Gruppen zusammengefasst werden. Threadgroups können Threads und Threadgroups enthalten. Es gibt eine Hierarchie von Threadgroups. Es kann mehrere Threadgroups nebeneinander geben. Man kann ganze Threadgroups als Daemon definieren. Man kann alle Threads einer Gruppe bestimmen. Man kann die maximale Priorität einer Threadgroup festlegen.

24 EDV Parallelprogrammierung 24 Die Klasse ThreadGroup Konstruktoren: public ThreadGroup(String name) public ThreadGroup(ThreadGroup parent, String name) public final void setDaemon(boolean daemon) definiert die ThreadGroup als Daemon, d.h. alle Threads der Gruppe sind Daemons public final void setMaxPriority(int pri) setzt die maximale Priorität der Threads der Gruppe public int activeCount() gibt die Anzahl der in der Gruppe aktiven Threads aus public int activeGroupCount() gibt die Anzahl der in der Gruppe aktiven ThreadsGroup´s aus public int enumerate(Thread[] list) gibt ein Feld aller aktiven Threads der Gruppe aus public int enumerate(ThreadGroup[] list) gibt ein Feld aller aktiven ThreadsGroup´s der Gruppe aus

25 EDV Parallelprogrammierung 25 Die Klasse ThreadGroup public final void interrupt() ruft interrupt-Methode alle aktiven Threads der Gruppe auf public void uncaughtException(Thread t, Throwable e) wird von der JVM aufgerufen, wenn von einem Thread der Gruppe die Ausnahme e ausgelöst wird

26 EDV Parallelprogrammierung 26 Anwendung bei QuickSort Problem: jeder Thread, der neue Threads erzeugt hat, wartet nach Erzeugung der Threads nur noch auf deren Ende um sich am nach Beendigung der erzeugten Thread selbst zu beenden. Dadurch entstehen viele aktive Threads (ca. 50%), die eigentlich nicht mehr aktiv zu sein brauchten. Aktive Threads blockieren Systemressourcen. Lösungsmöglichkeit: Einrichtung einer ThreadGroup und Erzeugung aller QuickSort- Threads in dieser Gruppe. Starten des QuickSort-Programms als Thread. Anschließend warten bis kein aktiver Thread mehr in der Gruppe ist.

27 EDV Parallelprogrammierung 27

28 EDV Parallelprogrammierung 28 public static ThreadGroup tg = new ThreadGroup("QuickSort"); new QuickSort(a, 0, a.length-1,c).start(); int tgn=0; while ( (tgn=tg.activeCount()) > 0) { try{Thread.sleep(100);} catch(InterruptedException ie){} }

30 EDV Parallelprogrammierung 30 Modellierung eines Kontos public class Konto { int kontostand; public Konto(int kontostand) { this.kontostand=kontostand; } void add(int wert) { int neuerWert=kontostand; try { Thread.sleep((int)(Math.random()*100)); } catch (InterruptedException e) { } neuerWert+=wert; kontostand=neuerWert; } }

31 EDV Parallelprogrammierung 31 Modellierung der Bank public class SimpleBank { static Konto [] konten = {new Konto(30),new Konto(50),new Konto(100)}; public void ueberweisung(int von, int nach, int betrag) { konten[von].add(-betrag); konten[nach].add(betrag); } public void kontostand() { for (int i=0;i

32 EDV Parallelprogrammierung 32 Modellierung des Angestellten public class Angestellter extends Thread { SimpleBank bank; int von, nach, betrag; public Angestellter(SimpleBank bank, int von, int nach, int betrag) { this.bank=bank; this.von=von; this.nach=nach; this.betrag=betrag; } public void run() { bank.ueberweisung(von, nach, betrag); bank.kontostand(); } }

33 EDV Parallelprogrammierung 33 Simulation der Überweisungen public class SimpleBankDemo { public static void main(String[] args) throws Exception { SimpleBank b = new SimpleBank(); Angestellter A1, A2, A3; b.kontostand(); for (int i=0;i<100;i++) { A1 = new Angestellter(b, 0, 1, 20); A2 = new Angestellter(b, 1, 2, 20); A3 = new Angestellter(b, 2, 0, 20); A1.start(); A2.start(); A3.start(); A1.join(); A2.join(); A3.join(); } b.kontostand(); } }

34 EDV Parallelprogrammierung 34 Resultat Bei jedem Test ergeben sich andere Resultate. Ursache: Bei der Überweisung wird erst der alte Kontostand, dann eine zufällige Zeit gewartet und dann erst der neue Kontostand berechnet und gespeichert. In der Wartezeit kann ein anderer Angestellter den alten Kontostand lesen und eine Kontoänderung durchführen. Lösung: Es muss verhindert werden, dass ein Konto, das von einem Angestellten geändert wird, von einem weiteren geändert werden kann. Dazu muss verhindert werden, dass die Methode add der Klasse Konto von mehreren anderen Programmen gleichzeitig benutzt wird. Das wird erreicht durch das Schlüsselwort synchronized vor der Methodendeklaration.

35 EDV Parallelprogrammierung 35 Modellierung eines Kontos public class Konto { int kontostand; public Konto(int kontostand) { this.kontostand=kontostand; } synchronized void add(int wert) { int neuerWert=kontostand; try { Thread.sleep((int)(Math.random()*100)); } catch (InterruptedException e) { } neuerWert+=wert; kontostand=neuerWert; } }

36 EDV Parallelprogrammierung 36 Synchronisation durch Monitore synchroinzed kann auch vor einem Block stehen: synchronized(objekt) {... } Das objekt heißt Sperre (Lock). Durch diese Form des sysnchronized-Blockes wird verhindert, dass der Block von zwei Threads betreten wird, die die selbe Sperre besitzen. Synchronized-Blöcke können geschachtelt werden. Spezialfälle: objekt==this : es wird auf das aktuelle Objekt synchronisiert, d.h. z.B. die add-Methode eines Kontos, darf nur einmal gleichzeitig aktiv sein. Andere Konten können aber parallel geändert werden. objekt==getClass() : der synchronisierte Block darf nur von einem Objekt dieser Klasse betreten werden. Günstig bei der Modifikation statischer Attribute. objekt==Thread.currentThread().getThreadGroup() : der synchronisierte Block darf nur von einem Objekt der selben ThreadGroup betreten werden.

37 EDV Parallelprogrammierung 37 Modellierung eines Kontos public class Konto { public static int count=0; int kontostand; public Konto(int kontostand){this.kontostand=kontostand;} void add(int wert) { synchronized(this){ int neuerWert=kontostand; try{Thread.sleep((int)(Math.random()*100));} catch (InterruptedException e){} neuerWert+=wert; kontostand=neuerWert; } synchronized(getClass()){ int c=count; try{Thread.sleep((int)(Math.random()*10));} catch (InterruptedException e){} count=++c; } } }

38 EDV Parallelprogrammierung 38 Synchronisierung mit wait / notify wait und notify sind Methoden der Klasse Object. Sie dürfen nur innerhalb von synchronized-Methoden aufgerufen werden. public final void wait() throws InterruptedException public final void wait(long timeout) throws InterruptedException public final void wait(long timeout, int nanos) throws InterruptedException wait versetzt den aktuellen Thread in den Wartezustande, bis entweder die Zeit abgelaufen ist, ihn ein anderer Thread in dieser Zeit aufgeweckt hat oder er in dieser Zeit von außen beendet wurde. public final void notify() notify weckt einen anderen Thread, der auf das Freiwerden des aktuellen Objektes als Sperre wartet.

39 EDV Parallelprogrammierung 39 Beispiel : Lager Es soll ein Lager modelliert werden. Das Lager hat eine feste Zahl von Stellplätzen. In unbestimmten Abständen kommen Produzenten, um ein Produkt einzulagern und Verbraucher, um ein Produkt abzuholen. Der Produzent muss warten, wenn das Lager voll ist, bis ein Verbraucher kommt. Der Verbraucher muss warten, wenn das Lager leer ist bis ein Produzent kommt. synchronized reicht nicht, da damit nur das gleichzeitige Betreten des Lagers durch mehrere Produzenten bzw. Verbraucher verhindert werden kann. Lösung: Verbraucher ruft wait() auf, solange das Lager leer ist. Produzent ruft wait() auf, solange das Lager voll ist. Verbraucher und Produzent rufen nach beendeter Arbeit notify auf, einen wartenden Verbraucher oder Produzenten zu aktivieren.

40 EDV Parallelprogrammierung 40 Modellierung des Lagers public class Lager{ private int maxValues = 10; private float [] values=new float[maxValues]; private int nextValue = 0; public synchronized void put(float value) { while (nextValue==maxValues) try{wait();}catch (InterruptedException ie){} values[nextValue]=value; System.out.println("put : "+value+" auf Platz "+nextValue); nextValue++; notify(); } public synchronized float get(){ while (nextValue==0) try{wait();}catch (InterruptedException ie){} nextValue--; float value = values[nextValue]; System.out.println("get : "+value+" von Platz "+nextValue); notify(); return value; } }

41 EDV Parallelprogrammierung 41 Modellierung des Verbrauchers public class Verbraucher extends Thread { Lager lager; public Verbraucher(Lager lager) { this.lager=lager; } public void run() { try{sleep((int)(Math.random()*1000));} catch(InterruptedException ie){} lager.get(); } }

42 EDV Parallelprogrammierung 42 Modellierung des Produzenten public class Produzent extends Thread { Lager lager; public Produzent(Lager lager) { this.lager=lager; } public void run() { try{sleep((int)(Math.random()*500));} catch(InterruptedException ie){} lager.put((float)Math.random()); } }

43 EDV Parallelprogrammierung 43 Modellierung des Gesamtprozesses public class LagerDemo { public static void main(String[] args) { Lager lager = new Lager(); for (int i=0;i<50;i++) { Verbraucher v = new Verbraucher(lager); v.start(); } for (int i=0;i<50;i++) { Produzent p = new Produzent(lager); p.start(); } } }

44 EDV Parallelprogrammierung 44 Verbindung von Threads über Pipes Es seien zwei Threads zu programmieren, wobei ein Thread Daten produziert und der andere Thread diese Daten nach dem FIFO- Prinzip verarbeitet. Zur Lösung dieses Problems bieten sich Pipes an. Pipes sind Datenströme, die gleichzeitig geschrieben und gelesen werden können, wobei die Daten die zuerst geschrieben werden auch wieder gelesen werden. Pipes besitzen einen Puffer. Ist der Puffer voll, wird der schreibende Thread angehalten, bis wieder Platz frei ist. Ist der Puffer leer, wartet der lesende Thread, bis wieder Daten verfügbar sind. Es gibt PipedInputStream/PipedOutputStream sowie PipedReader/PipedWriter.

45 EDV Parallelprogrammierung 45 Die Klassen PipedXXX Die Klassen sind von den entsprechenden Klassen aus java.io abgeleitet, d.h. PipedXXX extends XXX, d.h. sie können als Kern für BufferedXXX, ObjectXXX u.s.w. genutzt werden. Konstruktoren: PipedInputStream(PipedOutputStream src) PipedOutputStream(PipedInputStream snk) Methoden: public void connect(PipedOutputStream src) throws IOException public void connect(PipedInputStream snk) throws IOException

46 EDV Parallelprogrammierung 46 Beispiel: Datenproduzent import java.io.*; public class Produzent extends Thread{ BufferedWriter out; public Produzent(Writer out){ if (out instanceof BufferedWriter) this.out=(BufferedWriter)out; else this.out=new BufferedWriter(out); } public void run(){ try { for (int i=0;i<20;i++) { sleep((int)(Math.random()*1000)); System.out.println(i+" : "); out.write("Das ist Satz Nr. "+i); out.newLine(); out.flush(); } out.write("ende\n"); } catch(Exception e){} }}

47 EDV Parallelprogrammierung 47 Beispiel: Datenverbraucher import java.io.*; public class Verbraucher extends Thread{ BufferedReader in; public Verbraucher(Reader in){ if (in instanceof BufferedReader) this.in=(BufferedReader)in; else this.in=new BufferedReader(in); } public void run(){ try { for (int i=0;;i++) { String line=in.readLine(); System.out.println(line); if (line.equals("ende")) return; } } catch(Exception e){} } }

48 EDV Parallelprogrammierung 48 Beispiel: Kopplung import java.io.*; public class TestPipe { public static void main(String[] args) throws Exception { PipedWriter out = new PipedWriter(); PipedReader in = new PipedReader(out); Produzent p = new Produzent(out); Verbraucher v = new Verbraucher(in); v.start(); p.start(); } }


Herunterladen ppt "EDV2 - 01 - Parallelprogrammierung1 Parallelprogrammierung mit JAVA."

Ähnliche Präsentationen


Google-Anzeigen