Best Practices für moderne Multicore-Programmierung

Slides:



Advertisements
Ähnliche Präsentationen
Software Engeniering II
Advertisements

der Universität Oldenburg
Objektorientierte Programmierung
Imperative Programmierung
DVG Einfache Klassen Einfache Klassen. DVG Einfache Klassen 2 Strukturen Beispiel: Personendaten bestehen aus –String name –String vorname.
Einführung in die Programmierung Ausführbare Klassen
6.3 Ereignisbasierte Systeme Ereignis (event) : eine Ereignis-Quelle (event source, publisher) generiert Benachrichtigung (event notification), an der.
Verteilte Software - Java - Prozedurale Programmierung 1
Prof. Dr.-Ing. habil. B. Steinbach - Informatik / Softwaretechnologie und Programmierungstechnik - Institut für Informatik Verteilte Software - Java -
Ausnahmen HS Merseburg (FH) WS 06/07.
Threads Richard Göbel.
Java: Objektorientierte Programmierung
Java: Dynamische Datentypen
Java: Grundlagen der Objektorientierung
Vorlesung Informatik 2 Algorithmen und Datenstrukturen (02 – Funktionenklassen) Tobias Lauer.
3.1.4 Leser/Schreiber-Ausschluß (reader/writer exclusion)
Imperative Programmierung Funktionen und Parameter
Praxis-Repetitorium JAVA zusätzliche, ergänzende Lehrveranstaltung
PRJ 2007/1 Stefan Dissmann Motivation Problem: gleiche Datenstrukturen werden für verschiedene Objekte gebraucht: z.B. Listen von Studierenden, Kunden,
PKJ 2005/1 Stefan Dissmann Ausblick Es fehlen noch: Möglichkeiten zum Strukturieren größerer Programme Umgang mit variabler Zahl von Elementen Umgang mit.
PKJ 2005/1 Stefan Dissmann Rückblick auf 2005 Was zuletzt in 2005 vorgestellt wurde: Klassen mit Attributen, Methoden und Konstruktoren Referenzen auf.
Projektplan: Fachgebiet Software Engineering Übersicht © Albert Zündorf, Kassel University.
DVG Kommentare1 Kommentare. DVG Kommentare 2 Kommentare Es gibt zwei Arten von Kommentaren: einzeilige Kommentare // der Kommentar geht.
EDV Parallelprogrammierung1 Parallelprogrammierung mit JAVA.
DVG Kommentare 1 Kommentare. 2 Kommentare Es gibt zwei Arten von Kommentaren: einzeilige Kommentare // der Kommentar geht bis zum Ende der Zeile.
Java in 9 Folien Besser: Online-Buch Go to Java 2.
Seite 1 Interface - Konzept Ein Interface führt einen neuen Datentyp ein: interface Frau {... } Das Interface enthält Deklarationen ( keine Definitionen.
OO implementieren Teil IV Objekte erzeugen. © René ProbstModul 226IV - 2 Von der Klasse zum Objekt Plan Bau Objekt Klasse Instanzierung Objekt Das Objekt.
Javakurs FSS 2012 Lehrstuhl Stuckenschmidt
Entwicklung verteilter Anwendungen I, WS 13/14 Prof. Dr. Herrad Schmidt WS 13/14 Kapitel 1 Folie 2 Microsoft.NET Framework: Quelle:
Javakurs FSS 2012 Lehrstuhl Stuckenschmidt
Parallel Matrix Multiplication
Einfach und doppelt verkettete Listen in JAVA by Jens Weibler
Objectives Verstehen was unterDelegate verstanden wird
Learning By Doing Parallelverarbeitung Multithreading (Nebenläufigkeit) Alte Idee der Parallelverarbeitung statt rein sequentieller Prozesse Parallelverarbeitung.
Seminar aus Softwareentwicklung
JOMP
Parallelisierung für Multiprozessor-Maschinen Teil 2.
Parallelisierung für Multiprozessor-Maschinen
Javelin Internet-based parallel computing using Java.
Programmiervorkurs WS 2014/15 Methoden
Java-Kurs - 8. Übung Besprechung der Hausaufgabe.
CuP - Java Achte Vorlesung Entspricht ungefähr Kapitel 4.1 des Skriptums Montag, 28. Oktober 2002.
Parallele Programmierung im.NET Framework Darmstadt, Präsentation am Beispiel von C-Sharp (C#)  Wichtige Grundlagen  Generika, Delegate, Lambda,
Alois Schütte Advanced System Programming 2 Interprozeßkommunikation  2.1 JVM Ablaufumgebung  2.2 Java Native Interface (JNI)  Verwendung von.
Robuste Programme durch Ausnahmebehandlung
Übung Informatik I exercise01. 2 Inhaltsübersicht Nachbesprechung Übung 1 Individuelle Fragen/Bemerkungen.
2 Datenabstraktion Geheimnisprinzip:
Java-Kurs Übung Besprechung der Hausaufgabe
Threads in Java Threads  Sprachumfang von Java Der Java-Standard fordert nur die Unterstützung von Thread-Prioritäten. Es gibt keine Forderung bzgl.:
Abteilung für Telekooperation Softwareentwicklung 2 UE WS 2008/09 SE2UE_ Ausnahmen (Exceptions)
Microsoft Student Partner
Java Programme nur ein bisschen objektorientiert.
Vortrag Einführung in AspectJ. Gliederung 1 Einleitung 2 Querschnittsfunktionalitäten in AspectJ 2.1 Sprachelemente 3 Beispiel 4 Join Point Modell 5 Weaving.
Protokollieren, überwachen und verfolgen Vortrag zum Seminar „Aspektorientierte Programmierung“ von Andre Kaplick - 6. Juni 2016.
Einführung in AspectJ ● Inhalt: 1)Überblick 2)Elemente des crosscuttings in AspectJ 3)„Hello World“ in AspectJ 4)Wie Aspekte in Java verwoben werden 5)Join.
Konstruktoren.
Praktische Informatik 1
Objektorientierung Gliederung von Daten und Funktionen zu Objekten
„Was du ererbt von Deinen Vätern hast, erwirb es, um es zu besitzen.“
1.Event Queue.
Nksainf.ch/oinf.
Haupttitel der Präsentation
Raphael Fischer Informatik II - Übung 06 Raphael Fischer
Cäsar-Verschlüsselung
Cäsar-Verschlüsselung
Ein Referat von Sabrina Vissel, darleen paul und yannick fuchs
«Delegierter» Methoden Schablone Funktionszeiger
Tutorstunde 10.
Implementieren von Klassen
 Präsentation transkript:

Best Practices für moderne Multicore-Programmierung Jörg Hettel

Hochschule Kaiserslautern Drei Standorte: Kaiserslautern, Zweibrücken, Pirmasens OpenStreetMap

Agenda Allgemeine Parallelisierungsstrategien Java und Parallelisierung Einige Best Practices Take Home Message

Parallelisierungsstrategien

Parallelisierungsstrategien Strukturierungsprinzip Datenparallelität Task-Parallelität Synchron auf Datensammlungen Asynchron entlang von Datenflüssen © Jörg Hettel, Hochschule Kaiserslautern

Task-Parallelität Verschiedene Ausprägungen Task-Queue Task © Jörg Hettel, Hochschule Kaiserslautern

Synchrone Daten-Parallelität … … Data-Item … … © Jörg Hettel, Hochschule Kaiserslautern

Asynchrone Daten-Parallelität Daten-quelle Daten- verarbeitung Subscriber Daten-quelle Daten- verarbeitung Subscriber © Jörg Hettel, Hochschule Kaiserslautern

Blick über den Zaun Concurrency-Modelle: Thread-Programmierung Funktionale Programmierung Communicating Sequential Processes Aktoren Datenparallelität Event-Basierte Programmierung Reaktive Programmierung ... © Jörg Hettel, Hochschule Kaiserslautern

Java und Parallelisierung

Concurrency-Tools von Java Executoren Locks Thread Daten-strukturen Synchronisations-klassen Atomic-Variablen © Jörg Hettel, Hochschule Kaiserslautern

Concurrency-Tools von Java Arbeiten mit rudimentären "Concurrency-Tools" ist mühsam und fehleranfällig Problem: Mutable Shared State Falsche Synchronisation führt z.B. zu Deadlocks Nichtberücksichtigung von "Sichtbarkeitsregeln" führt zu inkonsistenten Daten Falsche Aufteilung der "Load" führt zu "Ressourcenverschwendung„ Stichwort: False Sharing Etc. © Jörg Hettel, Hochschule Kaiserslautern

Parallelisierungs-frameworks von Java Blick über den Zaun Concurrency-Modelle: Thread-Programmierung Funktionale Programmierung Communicating Sequential Processes Aktoren Datenparallelität Event-Basierte Programmierung Reaktive Programmierung ... Parallelisierungs-frameworks von Java © Jörg Hettel, Hochschule Kaiserslautern

Parallelisierungsstrategien (mit Java) Strukturierungsprinzip Task-Parallelität Datenparallelität Future CompletableFuture ForkJoin Synchron auf Datensammlungen Asynchron entlang von Datenflüssen Parallel Streams ForkJoin Pipe & Filter (mit BlockingQueues) Reactive Streams © Jörg Hettel, Hochschule Kaiserslautern

Parallelisierungsframeworks Einführung von Abstraktionen für die Multicore-Programmierung: High-Level-Frameworks Parallel Streams CompletableFuture-Klasse Flow-Klassen (+ Frameworks) Ziele: Einfache Implementierung einer Parallelverarbeitung zur Beschleunigung von Anwendungen Nutzung eines passenden Concurrency-Modells © Jörg Hettel, Hochschule Kaiserslautern

Parallelisierungsstrategien mit Java Definition: Task als Abstraktion für eine Sammlung von zusammengehörigen (abhängigen) Anweisungen Heuristik für die Parallelisierung Task-Parallelität Tasks, die keine Abhängigkeiten haben, können parallel ausgeführt werden Datenparallelität Ein Task bearbeitet eine Menge von Daten, wobei jedes Element auf die selbe Art und Weise verarbeitet wird Reaktive Streams Ausführung eines Tasks wird durch eine äußeres Signal "getriggert" © Jörg Hettel, Hochschule Kaiserslautern

Best Practices Task-Parallelität

Task-Parallelität Abhängigkeiten von Tasks legen die Parallelisierungs- möglichkeiten fest © Jörg Hettel, Hochschule Kaiserslautern

Java CompletableFuture CompletableFuture–Klasse für Task-Parallelität Definition von asynchronen nebenläufigen Abläufen Task 2a Task 1 Task 2b Task 3 Consumer © Jörg Hettel, Hochschule Kaiserslautern

Fire-and-Forget-Task Der Task 2 hat keine weiteren Abhängigkeiten mehr Kann asynchron ausgeführt werden! © Jörg Hettel, Hochschule Kaiserslautern

CompletableFuture-Idiom Umsetzung einer einfachen Task-Parallelität (fire-and-forget) Wichtig: Exceptions sollten immer explizit "behandelt" werden Oft ist es wichtig Zeitüberschreitungen zu melden Bemerkung: Der eigentliche Task wird nicht abgebrochen! CompletableFuture.runAsync( () -> { // asynchrone Ausführung // ... }) .orTimeout(2000, TimeUnit.MILLISECONDS) .exceptionally( (ex) -> { ... } ); © Jörg Hettel, Hochschule Kaiserslautern

Split-and-Join-Tasks Tasks besitzen keine lineare Abhängigkeiten © Jörg Hettel, Hochschule Kaiserslautern

Einfaches CompletableFuture-Idiom Einfaches Warten, bis asynchrone Ausführung beendet ist ... CompletableFuture<Double> task2CF = CompletableFuture.supplyAsync( () -> { } );   CompletableFuture<Double> task3CF = // UND-Verknüpfung CompletableFuture<Double> task4CF = task2CF.thenCombine(task3CF, (resTask2, resTask3) -> { } ); // ... R result = task4CF.join(); © Jörg Hettel, Hochschule Kaiserslautern

Paralleles IO (Variante 1) Don't do this!! Codesequenz entspricht einem blockierenden Aufruf Es werden die Threads des Common-Pool benutzt List<URL> urls = getURLs();   // VORSICHT parallele IO-Aufrufe ! // Sollte so nicht verwendet werden ! List<String> result = urls.parallelStream() .map( url -> request(url) ) .map( page -> parse(page) ) .collect( toList() ); © Jörg Hettel, Hochschule Kaiserslautern

Paralleles IO (Variante 1) List<URL> urls = getURLs(); int maxThreads = ...; ExecutorService executor = Executors.newFixedThreadPool( Math.min( urls.size(), maxThreads), new ThreadFactory() { // Erzeuge Daemon-Thread } ); // Asynchrones IO List<CompletableFuture<String>> futures = urls.stream() .map( url -> CompletableFuture.supplyAsync( () -> request(url), executor ) ) .map( future -> future.thenApplyAsync( page -> parse(page), executor ) ) .collect( toList() );   List<String> result = futures.stream() .map( CompletableFuture::join ) executor.shutdown(); © Jörg Hettel, Hochschule Kaiserslautern

Paralleles IO (Variante 1) Threadpool (Executor) request(url1) request(url2) … request(urln) parse(page1) parse(page2) … parse(pagen) collect String String … String join( ) © Jörg Hettel, Hochschule Kaiserslautern

Best Practices Datenparallelität

Verarbeitungs-ergebnis Datenparallelität Gleichförmige Verarbeitung einer "Datensammlung" "Map-Reduce"- bzw. "Map-Collect"-Prinzip Op1 Op2 Op3 Op1 Op2 Op1 Op2 Op1 Op2 Op3 … … … … Verarbeitungs-ergebnis Op1 Op2 Op3 Datensammlung © Jörg Hettel, Hochschule Kaiserslautern

Java-Streams „Java 8“-Streams für Daten-Parallelität Verarbeitung von Datensammlungen, wie z.B. Collections Entspricht einer „Pipeline“-Verarbeitung Daten-quelle Stream-erzeugung Stream-verarbeitung Stream-Auswertung Ergebnis aus Collections aus Iteratoren aus Generatoren ... map( … ) filter( … ) flatMap( … ) peek( … ) distinct() sorted() ... forEach( … ) findAny( … ) collect( … ) reduce( … ) ... © Jörg Hettel, Hochschule Kaiserslautern

Parallele Java-Streams Parallelisierung durch Fork/Join-Mechanismus Stream-verarbeitung Stream-verarbeitung Daten-quelle Ergebnis Stream-verarbeitung Stream-verarbeitung © Jörg Hettel, Hochschule Kaiserslautern

Bemerkungen zu Parallel-Streams Stream-Verarbeitung muss „seiteneffektfrei“ (parallel ready) sein! Das Speicherlayout kann eine große Rolle spielen Parallelisierung lohnt sich nur wenn Datenquelle effizient gesplittet werden kann wenn effizient „reduziert“ bzw. „gesammelt“ werden kann wenn genügend Arbeit (Daten) vorhanden ist Sowohl in den Split-Prozess als auch in den Reduce/Collect-Prozess kann „eingegriffen“ werden Benutzerdefinierte Spliteratoren bzw. Collectoren

Paralleles IO (Variante 2) Mit parallelen Streams, aber eigenem Threadpool (Executor) List<URL> urls = getURLs(); int maxThreads = ...; ForkJoinPool pool = new ForkJoinPool( Math.min( urls.size(), maxThreads ); // Asynchrones IO ForkJoinTask<List<String>> task = pool.submit( () -> urls.parallelStream() .map( url -> request(url) ) .map( page -> parse(page) ) .collect( toList() ) ); List<String> result = task.join(); pool.shutdown(); © Jörg Hettel, Hochschule Kaiserslautern

Benutzerdefinierte Collectoren Beispiel: Bestimme den Bestand der einzelnen Kategorien. Es gibt verschiedene Produkte, die jeweils einer Kategorie zugeordnet sind © Jörg Hettel, Hochschule Kaiserslautern

Formulierung mit Streams Naive Lösung (entspricht dem Bild) List<Produkt> produkte = ...;   Map<Kategorie, List<Produkt>> kategorieMap = produkte.stream() .collect( Collectors.groupingBy( Produkt::getKategorie) ); Map<Kategorie, Integer> kategorieSum = kategorieMap.entrySet() .stream() .collect( Collectors.toMap( entry -> entry.getKey(), entry -> entry.getValue() .mapToInt( Produkt::getMenge ).sum())); © Jörg Hettel, Hochschule Kaiserslautern

Downstream Collection List<Produkt> produkte = ...; Map<Kategorie, Integer> kategorieMap = produkte.stream() .collect( Collectors.groupingBy( Produkt::getKategorie, Collectors.summingInt( Produkt::getMenge)) ); © Jörg Hettel, Hochschule Kaiserslautern

Benutzerdefinierter Collector Gruppierung und Summation können zusammenngefasst werden class ProduktCollector implements Collector<...> { public Supplier<int[]> supplier() { return () -> new int[3]; // Drei Kategorien }   public BiConsumer<int[], Produkt> accumulator() { return (array, produkt) -> { // Zählt Kategorien }; public BinaryOperator<int[]> combiner() { return (left,right) -> { // Vereinigt Teilergebnisse };   ... © Jörg Hettel, Hochschule Kaiserslautern

Benchmark © Jörg Hettel, Hochschule Kaiserslautern

Beispiel Bildkompression

Prinzip der 2D-FFT Abbildung aus: Brunton und Kutz, Data-Driven Science and Engineering, Cambridge University Press © Jörg Hettel, Hochschule Kaiserslautern

2D-FFT-Bildkompression © Jörg Hettel, Hochschule Kaiserslautern

Verbesserungspotential Programmstart Anzeige der Vorschaubilder Berechnung der Bildkompression Reaktivität der Anwendung Beispiel: https://github.com/hettel/ImageCompression-CaseStudy © Jörg Hettel, Hochschule Kaiserslautern

Asynchrone Initialisierung der Hardware private CpuInfoPublisher publisher; @Override public void initialize(URL location, ResourceBundle resources) { clusterCount.addAll(1, 2, 3, 4, 5, 6, 7, 8, 9); ... cpuLoadBar.setFill(Color.GREEN); CompletableFuture.runAsync( () -> publisher = CpuInfoPublisher.getInstance(); publisher.subscribe(value -> Platform.runLater(() -> { repaintGradient(value); cpuLabel.setText(df.format(100 * value) + " %"); })); }).exceptionally( ex -> { ex.printStackTrace(); return (Void) null; }); } © Jörg Hettel, Hochschule Kaiserslautern

Erzeugung der Vorschaubilder File[] listOfFiles = imageFolder.listFiles( ... ); int numOfProcessors = Runtime.getRuntime().availableProcessors(); int numOfPoolThreads = Math.min( listOfFiles.length , numOfProc*16); ForkJoinPool pool = new ForkJoinPool(numOfPoolThreads); ForkJoinTask<List<ImageView>> task = pool.submit( () -> Arrays.stream(listOfFiles) .parallel() .map( FileIOHelper::createPreviewImage ) .map( FileIOHelper::createImageView ) .collect( toList() ) ); List<ImageView> resultList = task.join(); pool.shutdown();

Bildverarbeitungsprozess Bild- und FFT-Matrix-Anzeige Bilddatei einlesen und Graudarstellung berechnen Bild auf UI anzeigen Berechne FFT-Matrix FFT-Matrix anzeigen Matrixkoeffizienten sortieren © Jörg Hettel, Hochschule Kaiserslautern

Berechnung der FFTs

Bildverarbeitungsprozesse FFT-Transformation und Anzeige Lese Skalierung Berechne reduzierte FFT-Matrix Berechne reduziertes Bild Zeige Bild an Berechne Bild-Matrix Zeige Bild-Matrix © Jörg Hettel, Hochschule Kaiserslautern

Berechnung der FFTs

Problem: Nested Parallelism Bsp: Starten einer parallelen Stream-Verarbeitung in einem CompletableFuture Parallel Stream wird mit Threads des Pools ausgeführt, die das CompletableFuture ausführen ForkJoinPool pool1 = new ForkJoinPool(4); ForkJoinPool pool2 = new ForkJoinPool(4); CompletableFuture<Double> task1 = CompletableFuture.supplyAsync( () -> doWork1(), pool1 ); CompletableFuture<Double> task2 = CompletableFuture.supplyAsync( () -> doWork2(), pool2 ); CompletableFuture.allOf(task1, task2).join(); Benutzen parallele Streams © Jörg Hettel, Hochschule Kaiserslautern

Problem: Nested Parallelism Bsp: Starten eines asynchronen Task in einem asynchronen Task public static void main(String[] args) { CompletableFuture<String> task = CompletableFuture.supplyAsync( () -> doWork() ); System.out.println( task.join() ); } public static String doWork() CompletableFuture.runAsync( () -> System.out.println("work") ); return "done"; © Jörg Hettel, Hochschule Kaiserslautern

Structured Concurrency Analogie: Strukturierte Programmierung Programmcode entspricht dem Programmablauf (Dijkstra: GOTO considered harmful) Martin Sustrik: http://250bpm.com/blog:71 Nathaniel J. Smith: https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ © Jörg Hettel, Hochschule Kaiserslautern

Blick in die Zukunft Projekt Loom Projekt Valhalla Projekt Panama Fibers = lightweight user-mode threads Fibers = Continuations + Scheduling Respektiert: Structured Concurrency Projekt Valhalla Inline Types (Value Objects) Projekt Panama Vereinfachter nativer Funktionsaufruf Einbindung von OpenCL oder CUDA © Jörg Hettel, Hochschule Kaiserslautern

Take Home Message (1) Es gibt viele potentielle Stellen für den Einsatz von Parallelisierung Oft mehr als man auf den ersten Blick vermutet! Immer auch den Overhead beachten Frameworkeinsatz birgt auch Fehlerpotential Erschwert das Debugging und das "Code-Verstehen" Drei Parallelisierungsstrategien bei Java: Daten-Dekomposition Parallel Stream oder Fork/Join Task-Dekomposition CompletableFuture oder Future Asynchrone Daten-Auslieferungen Publish/Subscribe © Jörg Hettel, Hochschule Kaiserslautern

Take Home Message (2) Task-Parallelität (CompletableFuture) Besitzt großes Anwendungspotential "Seiteneffekte" und "Regeln" beachten Einsatz dokumentieren und nicht "übertreiben" Augenmerk auf Fehlersituationen legen Ggf. mit Timeouts arbeiten Daten-Parallelität (parallel Streams) Parallele Streams lohnen sich nicht immer © Jörg Hettel, Hochschule Kaiserslautern

Gibt es Fragen? Jörg Hettel Hochschule Kaiserslautern Campus Zweibrücken Fachbereich Informatik eMail: joerg.hettel@hs-kl.de