parallel programming condition queues klauserc/fs10/pp
TRANSCRIPT
![Page 1: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/1.jpg)
Parallel Programming
Condition Queues
http://n.ethz.ch/~klauserc/FS10/PP/
![Page 2: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/2.jpg)
Heute
1. Lösung zu Assignment 2
2. Condition Queues
Was sind Condition Queues?
Wann sind Condition Queues sinnvoll?
Wie verwendet man Condition Queues?
3. Ausblick auf Assignment 3
![Page 3: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/3.jpg)
1. – ASSIGNMENT 2
![Page 4: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/4.jpg)
Teil 2 – Fragen
Frage: Wieso reicht es nicht, die Methoden read und write `synchronized` zu machen?
Antwort: Dadurch wird nur verhindert, dass Producer und Consumer gleichzeitig schreiben/lesen. Hat keinen Einfluss auf die Reihenfolge der Operationen.
![Page 5: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/5.jpg)
Teil 2 – Fragen
Frage: Würde es ausreichen in den Methoden read und write anstelle von synchronized eine Bool’sche Variable als “Guard” zu verwenden?
Antwort: Nein! read und write sind keine atomaren Operationen!
Bonus: Warum ist i++ nicht atomar?
![Page 6: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/6.jpg)
Teil 3 – Fragen
Frage: Reicht synchronized(this) in den jeweiligen run-Methoden von Producer und Consumer?
Antwort: Nein, denn this ist jeweils an ein anderes Objekt gebunden. Zwei unabhängige locks Schliessen sich gegenseitig nicht aus
![Page 7: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/7.jpg)
Teil 3 – Fragen
Frage: Welches Objekt sollte stattdessen als gemeinsamer “Monitor” verwendet werden?
Antwort: Egal, solange beide das selbe Objekt verwenden. Am einfachsten nimmt man die gemeinsame Instanz von UnsafeBuffer.
![Page 8: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/8.jpg)
Source Code
![Page 9: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/9.jpg)
Teil 3 – FragenVorteile/Nachteile von Synchronisation der Producer/Consumer gegenüber Synchronisation des Buffers?
Vorteile:
Man kann beliebige Buffer verwenden (auch UnsafeBuffer)
Ermöglicht zusätzliche Aktionen, die ausgeführt werden müssen, bevor andere Threads den Buffer verwenden
Nachteile
Mehr Aufwand
Fehleranfällig (besonders wenn neue Prozesse hinzukommen)
![Page 10: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/10.jpg)
2. – CONDITION QUEUES
![Page 11: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/11.jpg)
Condition queue ≡ Intrinsic queue
• Eine Erweiterung des Monitor-Locks in Java
• Situation: Thread fährt nur unter folgenden Bedingungen fort
1. Exklusiven Zugriff auf eine Resource (Lock)
2. Preconditions erfüllt
Wie geht man mit Situationen um, wo (2.) nicht erfüllt ist?
![Page 12: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/12.jpg)
Conditiont Queue (Abstrakt)
void run() { //aquire lock while(!BEDINGUNG) { //release lock //let other threads fix precondition //re-aquire lock } //lock && precondition yay! … }
![Page 13: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/13.jpg)
Condition Queues (Konkret)
void run() { synchronized(this) { while(!BEDINGUNG) { wait(); //≡ this.wait() } //lock && precondition yay! … } //end-synchronized} //end-run
![Page 14: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/14.jpg)
Condition Queues - Kommunikation
synchronized void write(int d) { while(isFull) { wait(); } data = d;
isFull = true; notifyAll();}
synchronized int read() { while(!isFull) { wait(); } int d = data; isFull = false; notifyAll(); return d;}
![Page 15: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/15.jpg)
notify versus notifyAll
a.notifyAll weckt alle Threads, die auf a warten (via a.wait())
Die geweckten Threads verlangen alle exlusiven Lock auf a.
Konkurrieren auch mit allen anderen Threads, die diesen Lock wollen
Jeder Thread wird einmal die Chance haben, fortzufahren (Deadlock/Livelock ausgenommen)
![Page 16: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/16.jpg)
notify versus notifyAll
a.notify weckt einen (!) der Threads, die auf a warten (via a.wait())
Welcher der wartenden Threads aufgeweckt wird, hängt von der Implementierung ab (könnte auch zufällig sein)
Verlangen Lock auf a; konkurrieren mit allen anderen Threads, die ebenfalls Lock auf a wollen.
Andere wartende Threads bleiben wartend bis jemand sie “notified”
![Page 17: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/17.jpg)
notify vs. notifyAll - Empfehlung
• Einfacher Grundsatz: Immer notifyAll
• Erweiterter Grundsatz: Wenn ihr darüber nachdenken müsst, ob notify anstatt notifyAll funktioniert, nehmt notifyAll
• Szenario für notify: Es ist egal welcher Thread aufgeweckt wird.
Beispiel: Pool von Workerthreads. Es spielt keine Rolle welcher der Worker aufgeweckt wird. Jeder kann die Arbeit verrichten.
![Page 18: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/18.jpg)
ProducerFlagBuffer buf;void run() { for(int counter = 0;
counter < 10000; i++) { if(buf.isFull) { buf.wait(); } synchronized(buf) { buf.write(counter); buf.isFull = true; } }//end-for}//end-run
ConsumerFlagBuffer buf;void run() { while(true) { if(!buf.isFull) buf.wait(); synchronized(buf) { int counter = buf.read)); buf.isFull = false; if(counter >= 9999) { return; } } //consume counter … }//end-while}//end-run
Ist dieser Code korrekt?
![Page 19: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/19.jpg)
ProducerFlagBuffer buf;void run() { for(int counter = 0;
counter < 10000; i++) { synchronized(buf) { while(buf.isFull) buf.wait(); buf.write(counter); buf.isFull = true; notifyAll(); } //end-synchronized } //end-for} //end-run
ConsumerFlagBuffer buf;void run() { while(true) { synchronized(buf) { while(!buf.isFull) buf.wait(); int counter = buf.read)); buf.isFull = false; if(counter >= 9999) { return; } notifyAll(); } //end-synchronized //consume counter … } //end-while} //end-run
Ist dieser Code korrekt?
![Page 20: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/20.jpg)
ProducerFlagBuffer buf;void run() { synchronized(buf) { for(int counter = 0;
counter < 10000; i++) { while(buf.isFull) buf.wait(); buf.write(counter); buf.isFull = true; buf.notifyAll(); } //end-for }//end-synchronized}//end-run
ConsumerFlagBuffer buf;void run() { while(true) { synchronized(buf) { while(!buf.isFull) buf.wait(); int counter = buf.read)); buf.isFull = false; if(counter >= 9999) { return; } buf.notifyAll(); }//end-synchronized //consume counter … }//end-while}//end-run
Ist dieser Code korrekt?
![Page 21: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/21.jpg)
Richtig oder falsch?
• „notify() weckt nur einen der wartenden Threads, während notifyAll() alle weckt“
• „a.wait() darf nur aufgerufen werden, wenn der aktuelle Thread den Lock auf a hält.“
• „a.notify() weckt einen der auf a wartenden Threads und lässt ihn um den Lock auf a konkurrieren.“
![Page 22: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/22.jpg)
3. – ASSIGNMENT 3
![Page 23: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/23.jpg)
Mergesort
Gegeben:
Liste L mit n Zahlen (int)
Gesucht:
Sortierte Liste L’
Algorithmus:
Teile L auf in zwei Listen der Länge n/2
Sortiere jede der Unterlisten rekursiv mit Mergesort
Führe die zwei sortierten Unterlisten zusammen
Ende der Rekursion: Listen mit nur 1 Element
![Page 24: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/24.jpg)
Beispiel (Zerlegung)
5, 4, 3, 2, 1, 0
5, 4, 3 2, 1, 0
5, 4 3
5 4
2, 1 0
2 1
![Page 25: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/25.jpg)
Zusammenführen (merging)
Beispiel
L1: 0 5
L2: 3 4 45
Ausgabe:
Per Definition
0 3 4 5 45
Vergleichen
Kopieren
Zeiger bewegen
Fertig!
![Page 26: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/26.jpg)
Zusammenführen, Beispiel
0, 1, 2, 3, 4, 5
3, 4, 5 0, 1, 2
4, 5 3
5 4
1, 2 0
2 1
![Page 27: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/27.jpg)
Mergesort, parallelisiert
• Welche Teile des Algorithmus können parallelisiert werden?
Unterlisten sortieren
Zwei Unterlisten zusammenführen
• Synchronisationsprobleme?
Zwei Unterlisten erst zusammenführen, wenn sie fertig sortiert sind
• Performance
Anzahl Threads
Länge der Liste
![Page 28: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/28.jpg)
Performance-Messungn t 1 2 4 8 16 32 … 51
2100´000 ×
500´000 ×
1´000´000
⋮
100´000´000n ≔ Länge der Listet ≔ Anzahl Threads
Frage: Wieviele Threads sind optimal?
![Page 29: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/29.jpg)
Wie misst man Zeit?
• System.currentTimeMillis()
Nicht jede Millisekunde aktualisiert
Nicht auf Millisekunden genau
• System.nanoTime()
Präzision in Nanosekunden
Nicht auf Nanosekunden genau
• Für uns ist currentTimeMillis() gut genug
![Page 30: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/30.jpg)
Wie misst man Zeit
long start;long end;start = System.currentTimeMillis();//zu messender Vorgangend = System.currentTimeMillis();System.out.println(“Time elapsed: “ + (end-start));
![Page 31: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/31.jpg)
Auf einen Thread warten
Welche Möglichkeiten kennt ihr?
• Busy wait (in Schleife überprüfen, ob Thread fertig; Assignment 3)
• Condition Queues (wait(), notifyAll())
• Warten bis der Thread sich selbst beendet: t.join()
![Page 32: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/32.jpg)
t.join()
Thread t = new Thread(myRunnable);t.start();//do our own stuff in the meantimetry { t.join(); //wait for the other thread to „catch up“} catch(InterruptedException e) { /* ignore */ }
t.join();
t.start();
![Page 33: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/33.jpg)
Zu beantwortende Fragen
• Ist die parallele Version schneller?
Nicht selbstverständlich: Verwaltungsaufwand
• Wieviele Threads bieten optimale Performance?
• Welchen Einfluss haben
CPU Modell
CPU Taktfrequenz
Anzahl “Cores”
verfügbarer Arbeitsspeicher
verfügbarer Adressraum (32Bit vs. 64Bit)
![Page 34: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/34.jpg)
Unangenehme Realität
• Ideale Welt
N Prozessoren führen zu einem N-fachen Anstieg der Rechenleistung
• Realität
Jeder zusätzliche Prozessor muss auch verwaltet werden.
Viele Abläufe können erst gar nicht parallelisiert werden (rein Sequentiell)
Kommunikation/Synchronisation können Wartezeiten zur Folge haben
![Page 35: Parallel Programming Condition Queues klauserc/FS10/PP](https://reader035.vdocuments.us/reader035/viewer/2022081602/55204d7549795902118ca8d0/html5/thumbnails/35.jpg)
FRAGEN?