diff --git a/Programmierparadigmen.pdf b/Programmierparadigmen.pdf index a3a8b19..76538ae 100644 Binary files a/Programmierparadigmen.pdf and b/Programmierparadigmen.pdf differ diff --git a/Programmierparadigmen.tex b/Programmierparadigmen.tex index f0876bf..60c7080 100644 --- a/Programmierparadigmen.tex +++ b/Programmierparadigmen.tex @@ -2601,17 +2601,17 @@ $\lambda x.xx$ wendet sein Argument auf das Argument selbst an $\Rightarrow$ dad \begin{itemize*} \item Rekursive Funktion von g \begin{itemize*} - \item $g = \lambda n.…g…n…$ Rumpf verwendet g + \item $g = \lambda n...g...n...$ Rumpf verwendet g \end{itemize*} \item Daraus gewinnt man das Funktional \begin{itemize*} - \item $G = \lambda g.\lambda n.…g…n…$ + \item $G = \lambda g.\lambda n...g...n...$ \end{itemize*} \item Falls G einen Fixpunkt g* hat, d.h. $G(g*) = g*$, so \begin{itemize*} - \item $g* = G(g*) = \lambda n.…g*…n$ + \item $g* = G(g*) = \lambda n...g*...n$ \end{itemize*} - \item Vergleiche: $g = \lambda n.…g…n…$ + \item Vergleiche: $g = \lambda n...g...n...$ \end{itemize*} \begin{center} Rekursive Definition $\Leftrightarrow$ Fixpunkt des Funktionals @@ -2647,7 +2647,7 @@ $\lambda x.xx$ wendet sein Argument auf das Argument selbst an $\Rightarrow$ dad \begin{itemize*} \item Anfangsfunktionen: \begin{itemize*} - \item Projektion: $U_i^k (n_1,n_2,…,n_k) = n_i$ für $1<=i<=k$ + \item Projektion: $U_i^k (n_1,n_2,...,n_k) = n_i$ für $1<=i<=k$ \item Nullfunktion: $Z(n) = 0$ \item Nachfolger: $S(n) = n+1$ \end{itemize*} @@ -2656,15 +2656,15 @@ $\lambda x.xx$ wendet sein Argument auf das Argument selbst an $\Rightarrow$ dad \item Für eine Relation $P(m)$ bezeichne $\mu m[P(m)]$ die kleinste Zahl m sodass P(m) gilt. \end{itemize*} \end{itemize*} - \item Bemerkung: im Folgenden notieren wir $n_1,n_2,…,n_k$ kurz als $\overline{n_k}$ + \item Bemerkung: im Folgenden notieren wir $n_1,n_2,...,n_k$ kurz als $\overline{n_k}$ \item Eine numerische Funktion ist Lambda-definierbar, wenn es einen Kombinator M gibt, sodass $M\overline{n_k} = f(\overline{n_k})$ \end{itemize*} \begin{itemize*} - \item Im folgenden sei C eine Klasse von numerischen Funktionen, und es gelte $g,h,h_1,h_2,…,h_m \in C$ + \item Im folgenden sei C eine Klasse von numerischen Funktionen, und es gelte $g,h,h_1,h_2,...,h_m \in C$ \item Wir definieren nun die folgenden Eigenschaften: \begin{itemize*} - \item C ist \color{blue} abgeschlossen unter Komposition\color{black}, wenn für jede Funktion f, die über $f(\overline{n_k}):= g(h_1(\overline{n_k}),…,h_m(\overline{n_k}))$ definiert ist, gilt $f \in C$ + \item C ist \color{blue} abgeschlossen unter Komposition\color{black}, wenn für jede Funktion f, die über $f(\overline{n_k}):= g(h_1(\overline{n_k}),...,h_m(\overline{n_k}))$ definiert ist, gilt $f \in C$ \item C ist \color{blue} abgeschlossen unter primitiver Rekursion\color{black}, wenn für jede Funktion f, die über $$f(0,\overline{n_k}) = g(\overline{n_k})$$ $$f(j+1, \overline{n_k}) = h(f(j,\overline{n_k}),j,\overline{n_k})$$ @@ -2683,7 +2683,7 @@ $\lambda x.xx$ wendet sein Argument auf das Argument selbst an $\Rightarrow$ dad \item \color{blue} Lemma 1: Die Anfangsfunktionen sind Lambda-definierbar \color{black} \item Beweis: \begin{itemize*} - \item $U_i^k = \lambda x_1 x_2 … x_k.x_i$ + \item $U_i^k = \lambda x_1 x_2 ... x_k.x_i$ \item $S = \lambda n.\lambda s. \lambda z.s(nsz)$ (siehe succ bei Churchzahlen) \item $Z = \lambda fx.x$ (siehe $c_0$ bei Churchzahlen) \end{itemize*} @@ -2799,7 +2799,7 @@ $\lambda x.xx$ wendet sein Argument auf das Argument selbst an $\Rightarrow$ dad \item Hierbei ist es insbesondere von Interesse, wie Parameter gehandhabt werden, deren Werte undefiniert sind (z.B. 1/0)\newline \colorbox{lightgray}{ \begin{minipage}[h]{1.0\linewidth} - Wir definieren zunächst den zentralen begriff "strikt": \newline Eine n-stellige Funktion heißt strikt im k-ten Argument $(1<=k<=n)$, wenn gilt: $f(x_1,x_2,…,x_{k-1},\bot,x_{k+1},…,x_n)=\bot$ + Wir definieren zunächst den zentralen begriff "strikt": \newline Eine n-stellige Funktion heißt strikt im k-ten Argument $(1<=k<=n)$, wenn gilt: $f(x_1,x_2,...,x_{k-1},\bot,x_{k+1},...,x_n)=\bot$ \end{minipage}} \item Ein undefiniertes Argument führt hier zu einem undefinierten Resultat \item Grundsätzlich kann man die Auswertungsstrategien von Programmiersprachen in strikte und nicht-strikte Strategien einteilen; sehr gebräuchlich sind dabei insbesondere: @@ -2849,7 +2849,7 @@ $\lambda x.xx$ wendet sein Argument auf das Argument selbst an $\Rightarrow$ dad \item Die folgenden Gleichungen definieren eine nicht-strikte Multiplikation $\otimes$ auf der Basis der Multiplikation · für Zahlen: $$0 \otimes y = 0$$ $$x \otimes 0 = 0$$ - $$x \otimes y = x · y$$ + $$x \otimes y = x * y$$ \item Wenn ein Arguemnt undefiniert ist, dann liefert $\otimes$ ein Ergebnis, sofern das andere Argument zu 0 evaluiert wird ($\rightarrow fak(-1) \otimes (fak(3)-6)$) \item Implementiert werden kann die Funktion nur durch eine Art von paralleler Auswertung mit Abbruch der anderen Berechnung sobald 0 als Resultat berechnet und zurückgegeben wurde \end{itemize*} @@ -2899,10 +2899,10 @@ $\Rightarrow$ call-by-name, call-by-value \subsubitem $\Rightarrow (\lambda \color{blue}y\color{black}(\lambda x. \color{blue}y\color{black}(\lambda z.z)x))\color{red}(\lambda y.y)\color{black}$ \subsubitem $\Rightarrow (\lambda x.(\lambda y.y(\lambda z.z)x)) \nRightarrow$ \item Intuition: Argumente vor Funktionsaufruf auswerten - \item Auswertungsstrategie vieler Sprachen: Java, C, Scheme, ML, … + \item Auswertungsstrategie vieler Sprachen: Java, C, Scheme, ML, ... \item Arithmetik in Haskell: Auswertung by-value \item $prodOf(x) = y * prodOf x$ - \item $3 * prodOf 3 \Rightarrow 3 * (3 * prodOf 3) \Rightarrow$ … + \item $3 * prodOf 3 \Rightarrow 3 * (3 * prodOf 3) \Rightarrow$ ... \item $((div \space1 \space 0) * 6) * 0 \Rightarrow \bot$ \item $((div \space2 \space 2) * 6) * 0 \Rightarrow ((1 * 6) * 0) \Rightarrow 6 * 0\Rightarrow 0 \nRightarrow$ \end{itemize*} @@ -2974,7 +2974,7 @@ $\Rightarrow$ call-by-name, call-by-value \subsubsection{The free launch is over} Taktfrequenz wächst nur noch langsam \begin{itemize*} - \item Physikalische Gründe: Wärmeentwicklung, Energiebedarf, Kriechströme,… + \item Physikalische Gründe: Wärmeentwicklung, Energiebedarf, Kriechströme,... \end{itemize*} Auswege \begin{itemize*} @@ -3080,8 +3080,8 @@ $\Rightarrow$ call-by-name, call-by-value \begin{itemize*} \item Maße für Laufzeitgewinn durch Parallelisierung \item $T_n$ = Laufzeit des Programms mit n Prozessoren/Kernen - \item Speedup $Speedup = {{T_1} \over {T_n}}$ - \item Effizienz $Effizienz = {Speedup \over n}$ + \item Speedup $Speedup = \frac{T_1}{T_n}$ + \item Effizienz $Effizienz = \frac{Speedup}{n}$ \end{itemize*} \subsubsection{Amdahlsches Gesetz} @@ -3091,7 +3091,7 @@ $\Rightarrow$ call-by-name, call-by-value \item s = serieller Anteil \item n Prozessoren \item $p+s = 1$ - \item Maximaler Speedup $Speedup_{max} = {T_1 \over T_n} = {{s+p}\over{s+{p \over n}}} = {1 \over {s+{p \over n}}} = \frac{1}{s+\frac{p}{n}}$ + \item Maximaler Speedup $Speedup_{max} = \frac{T_1}{T_n} = {\frac{s+p}{s+ \frac{p}{n}}} = \frac{1}{s+\frac{p}{n}}$ \end{itemize*} \begin{center} \includegraphics[width=0.35\linewidth]{Assets/Programmierparadigmen-parallelisierung} @@ -3177,7 +3177,7 @@ $\Rightarrow$ call-by-name, call-by-value \includegraphics[width=0.9\linewidth]{Assets/Programmierparadigmen-Datenparallelität} \caption{Datenparallelität} \begin{itemize*} - \item homogene Datenmenge: Felder, Listen, Dokumentenmenge,… + \item homogene Datenmenge: Felder, Listen, Dokumentenmenge,... \item Verteilung der Daten \item alle Prozessoren führen gleiches Programm auf jeweils eigenen Daten aus \item Beispiel: Matrixaddition S = A + B @@ -3216,7 +3216,7 @@ $\Rightarrow$ call-by-name, call-by-value \begin{itemize*} \item Problemzerlegung \item Synchronisation - \item … + \item ... \end{itemize*} \item im Weiteren: konkrete Methoden und Techniken in Erlang und C++ \end{itemize*} @@ -3228,9 +3228,9 @@ $\Rightarrow$ call-by-name, call-by-value \item SMP-Support (Symmetric Multi Processing) \item Ziele für effiziente Parallelisierung \begin{itemize*} - \item Problem in viele Prozesse zerlegen (aber nicht zu viele …) - \item Seiteneffekte vermeiden (würde Synchronisation erfordern …) - \item Sequentiellen Flaschenhals vermeiden (Zugriff auf gemeinsame Ressourcen: IO, Registrierung von Prozessen, …) -> Small Messages, Big Computation! + \item Problem in viele Prozesse zerlegen (aber nicht zu viele ...) + \item Seiteneffekte vermeiden (würde Synchronisation erfordern ...) + \item Sequentiellen Flaschenhals vermeiden (Zugriff auf gemeinsame Ressourcen: IO, Registrierung von Prozessen, ...) -> Small Messages, Big Computation! \end{itemize*} \end{itemize*} @@ -3434,7 +3434,7 @@ $\Rightarrow$ call-by-name, call-by-value \subsubsection{Datenparallelität: Das Map-Reduce-Paradigma} \begin{itemize*} \item Parallelisierungsmuster inspiriert von Konzepten funktionaler Programmiersprachen (map,reduce/fold) - \item Basis von Big-Data-plattformen wie Hadoop, Spark,… + \item Basis von Big-Data-plattformen wie Hadoop, Spark,... \item Grundidee: \begin{itemize*} \item map(F, Seq) ? wende Funktion F (als Argument übergeben) auf alle Elemente einer Folge Seq an, @@ -3496,7 +3496,7 @@ $\Rightarrow$ call-by-name, call-by-value \begin{itemize*} \item Prozess für das Sortieren der einen Hälfte starten \item Elternprozess kann andere Hälfte sortieren - \item rekursive Zerlegung… + \item rekursive Zerlegung... \end{itemize*} \subsubsection{Parallel Quicksort} @@ -3695,7 +3695,7 @@ $\Rightarrow$ call-by-name, call-by-value \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-code-snippet-20} \end{center} \begin{itemize*} - \item Nutzung für Implementierung von Threadpools, Task Libraries, … + \item Nutzung für Implementierung von Threadpools, Task Libraries, ... \end{itemize*} \subsubsection{Probleme nebenläufiger Ausführung} @@ -3851,7 +3851,7 @@ $\Rightarrow$ call-by-name, call-by-value \begin{itemize*} \item Jeder greift die linke Gabel \item und wartet auf die rechte Gabel - \item … und wartet … + \item ... und wartet ... \end{itemize*} \begin{center} \includegraphics[width=0.3\linewidth]{Assets/Programmierparadigmen-philosophen} @@ -3883,37 +3883,37 @@ $\Rightarrow$ call-by-name, call-by-value \paragraph{Gabeln und Spaghetti-Teller} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-073} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-25} \end{center} \paragraph{Die Philosophen-Klasse} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-074} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-26} \end{center} \paragraph{Die Philosophen-Klasse: Hilfsmethoden} Textausgabe erfordert synchronisierten Zugriff auf cout über globalen Mutex \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-075} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-27} \end{center} Hilfsmethode für zufällige Wartezeit in Millisekunden \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-076} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-28} \end{center} \paragraph{Die Philosophen-Klasse: Essen} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-077} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-29} \end{center} \paragraph{Die Philosophen-Klasse: Denken} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-078} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-30} \end{center} \paragraph{Das Leben eines Philosophen} @@ -3922,13 +3922,13 @@ $\Rightarrow$ call-by-name, call-by-value \item Zur Erinnerung: überladener ()-Operator eines Objekts definiert auszuführende Funktion eines Threads \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-079} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-31} \end{center} \paragraph{Das Dinner: Initialisierung} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-080} + \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-code-snippet-32} \end{center} \paragraph{Das Dinner beginnt} @@ -3938,7 +3938,7 @@ $\Rightarrow$ call-by-name, call-by-value \item Philosophen-Threads arbeiten ihre operator()()-Methode ab \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-081} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-33} \end{center} \paragraph{Fazit} @@ -3965,7 +3965,7 @@ $\Rightarrow$ call-by-name, call-by-value \item typischer Anwendungsfall: Warten auf Ereignis / Setzen eines Flags \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-082} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-34} \end{center} \subsubsection{Bedingungsvariablen} @@ -3975,10 +3975,8 @@ $\Rightarrow$ call-by-name, call-by-value \item notwendig: synchronisierter Zugriff über Mutex \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-083} - \end{center} - \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-084} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-35} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-36} \end{center} \subsubsection{Thread-sichere Datenstrukturen} @@ -4008,7 +4006,6 @@ $\Rightarrow$ call-by-name, call-by-value \end{itemize*} \end{itemize*} - \subsubsection{Anforderungen} \begin{itemize*} \item mehrere Threads können gleichzeitig auf die Datenstruktur zugreifen @@ -4020,7 +4017,7 @@ $\Rightarrow$ call-by-name, call-by-value \subsubsection{Thread-sichere Queue} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-085} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-37} \end{center} \begin{itemize*} \item Zeilen 1,2,6: Kapselung der std::queue-Klasse @@ -4031,7 +4028,7 @@ $\Rightarrow$ call-by-name, call-by-value \paragraph{Thread-sichere Queue: Methode push} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-086} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-38} \end{center} \begin{itemize*} \item Zeile 2: Lock Guard sichert exklusiven Zugriff @@ -4042,7 +4039,7 @@ $\Rightarrow$ call-by-name, call-by-value \paragraph{Thread-sichere Queue: Methode waiting\_pop} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-087} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-39} \end{center} \begin{itemize*} \item Zeile 2: Lock Guard sichert exklusiven Zugriff @@ -4056,7 +4053,7 @@ $\Rightarrow$ call-by-name, call-by-value \item std::async() - asynchrones Starten eines Tasks \begin{center} \centering - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-088} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-40} \end{center} \item std::promise - erlaubt Wert zu setzen, wenn der aktuelle Thread beendet ist, of in Kombination mit std::future eingesetzt \item future = Ergbenisobjekt, promise = Ergebnisproduzent @@ -4072,20 +4069,19 @@ $\Rightarrow$ call-by-name, call-by-value \end{itemize*} \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-089} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-future-task} \end{center} - \paragraph{Beispiel} - + Beispiel \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-090} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-41} \end{center} \subsubsection{Deklarative Parallelisierung mit OpenMP} \begin{itemize*} \item Programmierschnittstelle für Parallelisierung in C/C++/Fortran \item Programmiersprachenerweiterung durch Direktiven - \item in C/C++: \#pragma omp … + \item in C/C++: \#pragma omp ... \item zusätzliche Bibliotheksfunktionen: \#include \item aktuelle Version 5.0 \item Unterstützung in gcc und clang @@ -4104,7 +4100,7 @@ $\Rightarrow$ call-by-name, call-by-value \item Fortsetzung des Master-Threads \end{itemize*} \begin{center} - \includegraphics[width=0.2\linewidth]{Assets/Programmierparadigmen-091} + \includegraphics[width=0.2\linewidth]{Assets/Programmierparadigmen-master-worker-thread} \end{center} @@ -4114,12 +4110,12 @@ $\Rightarrow$ call-by-name, call-by-value \item Ende des parallelen Abschnitts $\rightarrow$ implizite Synchronisation $\rightarrow$ Fortsetzung des Master-Threads \item der dem 'pragma' folgende Block wird parallel von allen Threads ausgeführt \begin{lstlisting}[language=C++] - \#include - \#include + #include + #include int main() { - \#pragma omp parallel + #pragma omp parallel { - std::cout << "Hello World from thread \#" + std::cout << "Hello World from thread #" << omp_get_thread_num() << " of " << omp_get_num_threads() << "\n"; } @@ -4129,26 +4125,26 @@ $\Rightarrow$ call-by-name, call-by-value \end{lstlisting} \item Schleifenparallelisierung: jedem Thread wird ein Teil der Iteration zugewiesen (beeinflusst nur äußere Schleife) \begin{lstlisting}[language=C++] - ... - \#pragma omp parallel for - for (int i = 0; i < 20; i++) {... + ... + #pragma omp parallel for + for (int i = 0; i < 20; i++) {... \end{lstlisting} \begin{itemize*} \item collapse(n) gibt an, dass n Schleifen in einem gemeinsamen Iterationsbereich zusammengefasst und auf die Threads verteilt werden sollen \begin{lstlisting} - #pragma omp parallel for collapse(3) - \end{lstlisting} + #pragma omp parallel for collapse(3) + \end{lstlisting} \end{itemize*} \item Beeinflussung der Thread Anzahl \begin{itemize*} \item maximale Anzahl: - \begin{lstlisting} + \begin{lstlisting} #pragma omp parallel for num_threads(8) -\end{lstlisting} + \end{lstlisting} \item bedingte Parallelisierung: - \begin{lstlisting} + \begin{lstlisting} #pragma omp parallel for if(i>50) -\end{lstlisting} + \end{lstlisting} \end{itemize*} \item Aufteilung des Iterationsbereichs; Beeinflussung durch schedule -Direktive \begin{itemize*} @@ -4162,7 +4158,7 @@ $\Rightarrow$ call-by-name, call-by-value \item '\#pragma omp single/master' Abschnitt wird nur durch einen/den Master-Thread ausgeführt \item '\#pragma omp critical' kritischer Abschnitt \item '\#pragma omp barrier' Warten auf alle Worker-Threads - \item '\#pragma omp atomic' kritischer Abschnitt \item Zugriff auf gemeinsame Variable (z.B. Zähler) + \item '\#pragma omp atomic' kritischer Abschnitt, Zugriff auf gemeinsame Variable (z.B. Zähler) \end{itemize*} \item Speicherklauseln für Variablen \begin{itemize*} @@ -4173,13 +4169,13 @@ $\Rightarrow$ call-by-name, call-by-value \end{itemize*} \item zuweisung von Programmabschnitten zu Threads $\rightarrow$ statische Parallelität (geeignet für rekursive Abschnitte) \begin{lstlisting}[language=C++] - \#pragma omp parallel sections - { - \#pragma omp section - qsort(data, left, p \item 1); - \#pragma omp section - qsort(data, p + 1, right); - } + #pragma omp parallel sections + { + #pragma omp section + qsort(data, left, p - 1); + #pragma omp section + qsort(data, p + 1, right); + } \end{lstlisting} \item Task Programmierung \begin{itemize*} @@ -4188,13 +4184,13 @@ $\Rightarrow$ call-by-name, call-by-value \item von beliebigem Thread definiert werden kann \end{itemize*} \begin{lstlisting}[language=C++] - unsigned int f1, f2; - \#pragma omp task shared(f1) - f1 = fib(f \item 1); - \#pragma omp task shared(f2) - f2 = fib(f \item 2); - \#pragma omp taskwait - return f1 + f2; + unsigned int f1, f2; + #pragma omp task shared(f1) + f1 = fib(f - 1); + #pragma omp task shared(f2) + f2 = fib(f - 2); + #pragma omp taskwait + return f1 + f2; \end{lstlisting} \end{itemize*} @@ -4203,7 +4199,7 @@ $\Rightarrow$ call-by-name, call-by-value \item der dem pragma folgende Block wird parallel von allen Threads ausgeführt \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-092} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-42} \end{center} \subsubsection{Schleifenparallelisierung} @@ -4212,17 +4208,18 @@ $\Rightarrow$ call-by-name, call-by-value \item für for-Schleifgen mit eingeschränkter Syntax (ganzzahlige Schleifenvariablen, Operatoren auf Schleifenvariablen) und für STL-Iteratoren \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-093} + \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-code-snippet-43} \end{center} + \subsubsection{Beeinflussung der Thread-Anzahl} maximale Anzahl \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-094} + \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-code-snippet-44} \end{center} \noindent bedingte Parallelisierung \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-095} + \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-code-snippet-45} \end{center} \subsubsection{Aufteilung des Iterationsbereichs} @@ -4234,7 +4231,7 @@ $\Rightarrow$ call-by-name, call-by-value \item schedule(static,n): statische Round-Robin-Verteilung - Bereiche der Größe n (Angabe von n ist optional) \item schedule(dynamic, n): dynamische Verteilung nach Bedarf \item schedule(guided, n): Verteilung nach Bedarf und proportional zur Restarbeit - \item … + \item ... \end{itemize*} \end{itemize*} @@ -4245,7 +4242,7 @@ $\Rightarrow$ call-by-name, call-by-value \item Beispiel: Matrizenmultiplikation \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-096} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-46} \end{center} \subsubsection{Synchronisation} @@ -4272,7 +4269,7 @@ $\Rightarrow$ call-by-name, call-by-value \item geeignet z.B. für rekursive Aufrufe \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-097} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-47} \end{center} \subsubsection{Task-Programmierung mit OpenMP} @@ -4285,7 +4282,7 @@ $\Rightarrow$ call-by-name, call-by-value \end{itemize*} \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-098} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-48} \end{center} \subsubsection{Fazit} @@ -4293,18 +4290,15 @@ $\Rightarrow$ call-by-name, call-by-value \item C++ bietet weitreichende und mächtige Konzepte zur Parallelisierung \begin{itemize*} \item von Basiskontrolle wie Threads und Synchronisationsprimitiven (u.a. Mutexe) - \item …über höherwertige Abstraktionen wie async, Features und Promises + \item ...über höherwertige Abstraktionen wie async, Features und Promises \item bis hin zu deklarativen Ansätzen wie OpenMP \end{itemize*} \item alle Formen von Parallelität (Instruktions-, Daten-, und Taskparallelität) möglich \item aber anspruchsvolle Programmierung - \item erleichtert durch zusätzliche Bibliotheken und Frameworks wie Parallel STL, TBB, … + \item erleichtert durch zusätzliche Bibliotheken und Frameworks wie Parallel STL, TBB, ... \end{itemize*} - \begin{lstlisting}[ -language=java, -showspaces=false, -basicstyle=\ttfamily -] + +\begin{lstlisting}[language=java] //[Hello.java] package runnable; public class Hello { @@ -4327,13 +4321,8 @@ public class Hello { } } \end{lstlisting} - \hfill - - \begin{lstlisting}[ -language=C++, -showspaces=false, -basicstyle=\ttfamily -] +\hfill +\begin{lstlisting}[language=C++] //[Hello.cpp] #include // Datei iostream aus System-Includes #include "X.hpp" // Datei X.hpp aus Projekt-Ordner @@ -4367,13 +4356,8 @@ int main(int argc, char* argv[]){ return 0; } \end{lstlisting} - \hfill - - \begin{lstlisting}[ -language=erlang, -showspaces=false, -basicstyle=\ttfamily -] +\hfill +\begin{lstlisting}[language=erlang] %[Hello.erl] -module(cheat_sheet). % end with a period @@ -4441,11 +4425,7 @@ countdown() $\rightarrow$ \begin{itemize*} \item Methode \textbf{public void run()} - wird beim Start des Threads aufgerufen \end{itemize*} - \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-099} - \end{center} - \begin{lstlisting}[ - language=java] + \begin{lstlisting}[language=java] public class Heartbeat implements Runnable { int pulse; public Heartbeat(int p) { pulse = p * 1000; } @@ -4457,15 +4437,10 @@ countdown() $\rightarrow$ } } } + \end{lstlisting} - public static void main(String[] args) { - Thread t = new Thread(new Heartbeat(2)); //Thread Objekt mit runnable erzeugen - t.start(); //methode start() aufrufen $\rightarrow$ ruft run() auf - } -\end{lstlisting} - \paragraph{Thread-Erzeugung} - + \begin{itemize*} \item Thread-Objekt mit Runnable-Objekt erzeugen \item Methode \textbf{start()} aufrufen @@ -4473,9 +4448,12 @@ countdown() $\rightarrow$ \item Ruft \textbf{run()} auf \end{itemize*} \end{itemize*} - \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-100} - \end{center} + \begin{lstlisting}[language=java] + public static void main(String[] args) { + Thread t = new Thread(new Heartbeat(2)); //Thread Objekt mit runnable erzeugen + t.start(); //methode start() aufrufen $\rightarrow$ ruft run() auf + } + \end{lstlisting} \paragraph{Subklasse von Thread} @@ -4484,7 +4462,7 @@ countdown() $\rightarrow$ \item Methode run() muss überschrieben werden \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-101} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-49} \end{center} \begin{itemize*} @@ -4495,52 +4473,32 @@ countdown() $\rightarrow$ \end{itemize*} \begin{center} \centering - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-102} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-50} \end{center} \item Spätere Beeinflussung durch andere Threads möglich \begin{center} \centering - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-103} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-51} \end{center} \end{itemize*} \paragraph{Threads: Wichtige Methoden} - \begin{itemize*} - \item void start(): initiiert Ausführung des Threads durch Aufruf der Methode run - \item void run(): die eigentliche Arbeitsmethode - \item static void sleep(int millis): hält die Ausführung des aktuellen Threads für 'millis' Millisekunden an; Keinen Einfluss auf andere Threads! - \item void join(): blockiert den aufrufenden Thread so lange, bis der aufgerufene Thread beendet ist - \end{itemize*} - - \begin{itemize*} - \item \textbf{void start()} - \begin{itemize*} - \item initiiert Ausführung des Threads durch Aufruf der Methode run - \end{itemize*} - \item \textbf{void run()} - \begin{itemize*} - \item die eigentliche Arbeitsmethode - \end{itemize*} - \item \textbf{static void sleep(int millisec)} - \begin{itemize*} - \item hält die Ausführung des aktuellen Threads für millisec Millisekunden an - \item Hat keinen Einfluss auf andere Threads! - \end{itemize*} - \item \textbf{void join()} - \begin{itemize*} - \item blockiert den aufrufenden Thread so lange, bis der aufgerufene Thread beendet ist - \end{itemize*} - \end{itemize*} + \begin{description*} + \item[void start()] initiiert Ausführung des Threads durch Aufruf der Methode run + \item[void run()] die eigentliche Arbeitsmethode + \item[static void sleep(int millis)] hält die Ausführung des aktuellen Threads für 'millis' Millisekunden an; Keinen Einfluss auf andere Threads! + \item[void join()] blockiert den aufrufenden Thread so lange, bis der aufgerufene Thread beendet ist + \end{description*} \subsubsection{Parallele Berechnung von Fibonacci-Zahlen} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-104} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-52} \end{center} Thread-Erzeugung und Ausführung \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-105} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-53} \end{center} \subsubsection{Wechselseitiger Ausschluss in Java} @@ -4555,14 +4513,14 @@ countdown() $\rightarrow$ \begin{itemize*} \item nur ein Thread darf diese Methode auf einem Objekt zur gleichen Zeit ausführen \end{itemize*} - \item für Anweisungen: \textbf{synchronized(anObject)\{…\}} + \item für Anweisungen: \textbf{synchronized(anObject)\{...\}} \begin{itemize*} \item nur ein Thread darf den Block betreten \item Sperre wird durch das Objekt \textbf{anObject} verwaltet (jedem Java-Objekt ist eine Sperre zugeordnet) \end{itemize*} \end{itemize*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-106} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-java-synchronized} \end{center} \begin{itemize*} \item Schlüsselwort synchronized @@ -4584,23 +4542,14 @@ countdown() $\rightarrow$ \end{itemize*} \subsubsection{wait \& notify} - \begin{itemize*} - \item Signalisierung zwischen Threads in Java - \item Basismethoden der Klasse \textbf{java.lang.Object} - \item \textbf{wait()}: der aktive Thread wartet an diesem Objekt, Sperren werden ggf. freigegeben. - \item \textbf{notify()}: wekct an diesem Objekt wartenden Thread auf - \item \textbf{notifyAll()}: weckt alle an diesem Objekt wartenden Threads auf - \item \textbf{wait() \& notify()} dürfen nur in einem \textbf{synchronized}-Block aufgerufen werden - \end{itemize*} - - \begin{itemize*} - \item Signalisierung zwischen Threads in Java - \item Basismethoden der Klasse java.lang.Object - \item wait() : der aktive Thread wartet an diesem Objekt, Sperren werden ggf. freigegeben! - \item notify() : weckt an diesem Objekt wartenden Thread auf - \item notifyAll() : weckt alle an diesem Objekt wartenden Threads auf - \item wait() \& notify() dürfen nur in einem synchronized -Block aufgerufen werden - \end{itemize*} + \begin{description*} + \item[] Signalisierung zwischen Threads in Java + \item[] Basismethoden der Klasse \textbf{java.lang.Object} + \item[wait()] der aktive Thread wartet an diesem Objekt, Sperren werden ggf. freigegeben. + \item[notify()] wekct an diesem Objekt wartenden Thread auf + \item[notifyAll()] weckt alle an diesem Objekt wartenden Threads auf + \item[wait() \& notify()] dürfen nur in einem \textbf{synchronized}-Block aufgerufen werden + \end{description*} \subsubsection{Java: High-Level-Klassen} \begin{itemize*} @@ -4619,12 +4568,9 @@ countdown() $\rightarrow$ \item Task = logische Ausführungseinheit \item Thread = Mechanismus zur asynchronen/parallelen Ausführung von Tasks \end{itemize*} - \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-107} - \end{center} - \begin{lstlisting}[ - language=java] -Runnable task = () $\rightarrow$ { + +\begin{lstlisting}[language=java] +Runnable task = () -> { String me = Thread.currentThread().getName(); System.out.println("Hallo " + me); }; @@ -4642,8 +4588,8 @@ thread.start(); \end{itemize*} \item Starten einer Aufgabe mit \textbf{submit} \begin{itemize*} - \item \textbf{Future submit(Callable c)} - \item \textbf{Future submit(Runnable r)} + \item \textbf{$Future$ submit(Callable c)} + \item \textbf{$Future$ submit(Runnable r)} \end{itemize*} \item Zugriff auf das Ergebnis mit \textbf{get} \begin{itemize*} @@ -4655,7 +4601,7 @@ thread.start(); \paragraph{Future \& ExecutorService: Beispiel} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-108} + \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-code-snippet-54} \end{center} \subsubsection{RecursiveAction \& Fork/Join} @@ -4664,10 +4610,6 @@ thread.start(); \item Solange bis Problem klein genug um direkt ausgeführt werden zu können \item Task erstellt zwei oder mehr Teiltasks von sich selbst $\rightarrowtail$ Datenparallelität \item ForkJoinPool zum Ausführen $\rightarrow$ implementiert Executor Interface - \item \textbf{ForkJoinPool} zum Ausführen - \begin{itemize*} - \item implementiert \textbf{Executor} Interface - \end{itemize*} \item Fazit \begin{itemize*} \item Parallelprogrammierung in Java sehr ähnlich zu C++ @@ -4684,7 +4626,7 @@ thread.start(); \paragraph{Beispiel} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-109} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-55} \end{center} Starten der Verarbeitung: \begin{enumerate*} @@ -4693,24 +4635,12 @@ thread.start(); \item Aufgabe vom Pool ausführen lassen \end{enumerate*} \begin{center} - \includegraphics[width=0.7\linewidth]{Assets/Programmierparadigmen-110} + \includegraphics[width=0.4\linewidth]{Assets/Programmierparadigmen-code-snippet-56} \end{center} - \subsubsection{Fazit} - \begin{itemize*} - \item Parallelprogrammierung in Java sehr ähnlich zu C++ - \item Konzepte: Threads, kritische Abschnitte über \textbf{synchronized} - \item mächtige Abstraktionen in \textbf{java.util.concurrent} - \begin{itemize*} - \item Tasks und Futures, Executor und Threadpool - \item thread-sichere Datenstrukturen - \item Synchronisation: Barrieren, Semaphoren,… - \end{itemize*} - \end{itemize*} - \subsection{Zusammenfassung} \begin{itemize*} - \item Parallelprogrammierung als wichtige Technik zur Nutzung moderner Hardware (Multicore, GPU, …) + \item Parallelprogrammierung als wichtige Technik zur Nutzung moderner Hardware (Multicore, GPU, ...) \item verschiedene Architekturen und Programmiermodelle \item Instruktions-, Daten- und Taskparallelität \item Message Passing vs. gemeinsamer Speicher @@ -4764,18 +4694,17 @@ thread.start(); \begin{itemize*} \item Datei \~/.erlang.cookie \item Erlang-Funktion - \begin{lstlisting}[ - language=erlang, - ]:set_cookie(node(), Cookie). - \end{lstlisting} + \begin{lstlisting}[language=erlang] + :set_cookie(node(), Cookie). + \end{lstlisting} \item Option \begin{lstlisting} - erl -setcookie Cookie - \end{lstlisting} + erl -setcookie Cookie + \end{lstlisting} \end{itemize*} \item Verbindungsaufbau mittels Funktion \begin{lstlisting} - net_adm:ping(adress) + net_adm:ping(adress) \end{lstlisting} \end{itemize*} @@ -4847,7 +4776,7 @@ thread.start(); \end{itemize*} \item Knoten sind über Netzwerke verbunden \begin{itemize*} - \item LAN(Wohnräume, Büros,…): bis zu 10 Gbit/s + \item LAN(Wohnräume, Büros,...): bis zu 10 Gbit/s \item MAN(Metropolitan Area Network, Behördennetze, dicht besiedelte Regionen): bis zu 10 Gbit/s \item WAN(Wide Area Network, weltweite Vernetzung): hohe Kapazitäten zwischen den ISPs \end{itemize*} @@ -4882,8 +4811,8 @@ thread.start(); \item Middlewaresysteme: Hardware, OS, Middleware, Anwendung \begin{itemize*} \item verteilte Dienste - \item Programmierparadigmen: RPC, Client/Server,… - \item Java, CORBA, … + \item Programmierparadigmen: RPC, Client/Server,... + \item Java, CORBA, ... \end{itemize*} \item Heute: Virtualisierung \begin{itemize*} @@ -4906,9 +4835,9 @@ thread.start(); \color{orange} $\Rightarrow$ brauchen Modelle zur Beschreibung der Kommunikation \color{black} \subsubsection{Anforderungen} - \color{orange} Anforderungen an Kommunikationsmodelle in … \color{black} + \color{orange} Anforderungen an Kommunikationsmodelle in ... \color{black} \newline - … verteilten Systemen\newline \newline + ... verteilten Systemen\newline \newline \begin{itemize*} \item Korrektheit \item Sicherheit @@ -4917,7 +4846,7 @@ thread.start(); \item Heterogenität \end{itemize*} - …verteilten Verkehrsmanagementsystemen\newline \newline + ...verteilten Verkehrsmanagementsystemen\newline \newline \begin{itemize*} \item Echtzeitfähigkeit \item Offenheit @@ -5037,9 +4966,9 @@ thread.start(); \end{itemize*} \item Programmbestandteile im Aktormodell \begin{itemize*} - \item Verhaltensdefinition $\Rightarrow$ f() $\rightarrow$ … end. - \item Erzeugen neuer Aktoren $\Rightarrow$ Pid = spwan(fun …). - \item Empfangen von Nachrichten $\Rightarrow$ receive … end. + \item Verhaltensdefinition $\Rightarrow$ f() $\rightarrow$ ... end. + \item Erzeugen neuer Aktoren $\Rightarrow$ Pid = spwan(fun ...). + \item Empfangen von Nachrichten $\Rightarrow$ receive ... end. \item Senden $\Rightarrow$ Pid ! Request. \end{itemize*} \item kein globaler Zustand @@ -5144,7 +5073,7 @@ ok \end{center} drei Prozesse mit \textbf{initialize(ErrorRate, NumberOfMessages, ReceiverPid, SenderPid, ChannelPid)} initialisieren und starten \begin{itemize*} - \item Sender hat vier Zustandsfunktionen; Startet mit senderReady0(List): Liste mit Zahlen 1,…,NumberOfMessages + \item Sender hat vier Zustandsfunktionen; Startet mit senderReady0(List): Liste mit Zahlen 1,...,NumberOfMessages \item Kanal: Nachricht "verlieren", wenn Zufallszahl $\ngeq$ ErrorRate \item Empfänger hat zwei Zustandsfunktionen; zu Beginn wird receiverWait0 gestartet \item initialize wartet auf eine ready-Nachricht; sendet danach stop-Nachrichten an alle @@ -5476,7 +5405,7 @@ end \item Clients: "Gib mir alle Personen, die älter als 18 Jahre alt sind" \end{itemize*} \item \textbf{Web}: Webserver stellt HTML Dokumente bereit, Brwoser ruft URLs für Dokumente auf - \item \textbf{E-Mail}: Mailserver verwalten Postfächer, leiten Mails weiter, Outlook/Thunderbird/…senden/lesen von Emails + \item \textbf{E-Mail}: Mailserver verwalten Postfächer, leiten Mails weiter, Outlook/Thunderbird/...senden/lesen von Emails \item Namensdienste (DNS), Fileserver, Zeitserver (NTP) \end{itemize*} @@ -5579,7 +5508,7 @@ end \item oftmals existiert ein HTTP Server / Anwendungsserver schon \item Idee: Jede Ressource die vom Server angeboten wird, ist durch eine URI beschrieben/identifiziert \begin{itemize*} - \item Datei, ein Eintrag in einer Datenbank, Tweet,… + \item Datei, ein Eintrag in einer Datenbank, Tweet,... \end{itemize*} \item Anlegen, Lesen, Verändern, Löschen (CRUD) \begin{itemize*} @@ -5599,7 +5528,7 @@ end \item bei jeder Anfrage werden alle Informationen gesendet \end{itemize*} \item Einheitliche Schnittstelle: über HTTP Standardmethoden auf Ressourcen zugreifen - \item Entkopplung von Ressource und Repräsentation: Ressourcen können in verschiedenen Formaten angeboten werden (JSON, XML,…) + \item Entkopplung von Ressource und Repräsentation: Ressourcen können in verschiedenen Formaten angeboten werden (JSON, XML,...) \end{enumerate*} \paragraph{HTTP Methoden für REST} @@ -5636,7 +5565,7 @@ end \begin{itemize*} \item manuelle Implementierung recht aufwändig \begin{itemize*} - \item unterscheiden von HTTP Methoden (GET, POST,…) + \item unterscheiden von HTTP Methoden (GET, POST,...) \item parsen/prüfen von URL Pfaden und Parametern \item setzen von Antwortheadern \& Kodierung in XML/JSON \end{itemize*} @@ -5687,7 +5616,7 @@ end https://reques.in kostenloser Dienst zum Testen von REST-Clients \begin{itemize*} - \item Variante 1: telnet reques.in 80 … + \item Variante 1: telnet reques.in 80 ... \item Variante 2: Auf der Kommandozeile \newline \$ curl https://reqres.in/api/users/1 \begin{center} @@ -6066,7 +5995,7 @@ fileservice.proto \begin{itemize*} \item erhebliche Management-Last beim Vermittler \begin{itemize*} - \item potentieller Engpass, SPoF - es sei denn… + \item potentieller Engpass, SPoF - es sei denn... \end{itemize*} \end{itemize*} Variante: mehrere Vermittler-Instanzen parallel und verteilt in einer Clusterumgebung