Multithreading fix
This commit is contained in:
parent
bd21045741
commit
3cd4b5951e
Binary file not shown.
@ -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 <omp.h>
|
||||
\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 <iostream>
|
||||
\#include <omp.h>
|
||||
#include <iostream>
|
||||
#include <omp.h>
|
||||
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 <iostream> // 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<T> submit(Callable c)}
|
||||
\item \textbf{Future<?> submit(Runnable r)}
|
||||
\item \textbf{$Future<T>$ 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
|
||||
|
Loading…
Reference in New Issue
Block a user