Parallele Berechnungen



Ähnliche Dokumente
Grundlagen der Programmierung 2. Parallele Verarbeitung

Grundlagen der Programmierung 2. Parallele Verarbeitung

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Grundlagen der Programmierung 2. Bäume

Primzahlen und RSA-Verschlüsselung

Informationsblatt Induktionsbeweis

Parallele Algorithmen und deren Ressourcenbedarf

1 topologisches Sortieren

Datenbanken Kapitel 2

Übersicht. Nebenläufige Programmierung. Praxis und Semantik. Einleitung. Sequentielle und nebenläufige Programmierung. Warum ist. interessant?

Lineare Gleichungssysteme

Beweisbar sichere Verschlüsselung

Speicher in der Cloud

Sortierverfahren für Felder (Listen)

7 Rechnen mit Polynomen

Kapitel 6. Komplexität von Algorithmen. Xiaoyi Jiang Informatik I Grundlagen der Programmierung

Konzepte der Informatik

AGROPLUS Buchhaltung. Daten-Server und Sicherheitskopie. Version vom b

1 Mathematische Grundlagen

6.2 Scan-Konvertierung (Scan Conversion)

Stellen Sie bitte den Cursor in die Spalte B2 und rufen die Funktion Sverweis auf. Es öffnet sich folgendes Dialogfenster

Folge 19 - Bäume Binärbäume - Allgemeines. Grundlagen: Ulrich Helmich: Informatik 2 mit BlueJ - Ein Kurs für die Stufe 12

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Grundlagen der Theoretischen Informatik, SoSe 2008

Systeme 1. Kapitel 6. Nebenläufigkeit und wechselseitiger Ausschluss

TESTEN SIE IHR KÖNNEN UND GEWINNEN SIE!

50. Mathematik-Olympiade 2. Stufe (Regionalrunde) Klasse Lösung 10 Punkte

Objektorientierte Programmierung

Kompetitive Analysen von Online-Algorithmen

Plotten von Linien ( nach Jack Bresenham, 1962 )

Gleichungen Lösen. Ein graphischer Blick auf Gleichungen

Kapiteltests zum Leitprogramm Binäre Suchbäume

Die Gleichung A x = a hat für A 0 die eindeutig bestimmte Lösung. Für A=0 und a 0 existiert keine Lösung.

OECD Programme for International Student Assessment PISA Lösungen der Beispielaufgaben aus dem Mathematiktest. Deutschland

Einführung in die Java- Programmierung

Erwin Grüner

Programmieren I. Kapitel 7. Sortieren und Suchen

Skript und Aufgabensammlung Terme und Gleichungen Mathefritz Verlag Jörg Christmann Nur zum Privaten Gebrauch! Alle Rechte vorbehalten!

Würfelt man dabei je genau 10 - mal eine 1, 2, 3, 4, 5 und 6, so beträgt die Anzahl. der verschiedenen Reihenfolgen, in denen man dies tun kann, 60!.

Berechnung der Erhöhung der Durchschnittsprämien

Anmerkungen zur Übergangsprüfung

Zeichen bei Zahlen entschlüsseln

4. Jeder Knoten hat höchstens zwei Kinder, ein linkes und ein rechtes.

Windows. Workshop Internet-Explorer: Arbeiten mit Favoriten, Teil 1

Wie halte ich Ordnung auf meiner Festplatte?

4 Aufzählungen und Listen erstellen

Algorithmen und Datenstrukturen. Große Übung vom Nils Schweer

Repetitionsaufgaben Wurzelgleichungen

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

3.2 Binäre Suche. Usr/local/www/ifi/fk/menschen/schmid/folien/infovk.ppt 1

Wie Sie mit Mastern arbeiten

Handbuch. NAFI Online-Spezial. Kunden- / Datenverwaltung. 1. Auflage. (Stand: )

Wir arbeiten mit Zufallszahlen

Einführung in die Algebra

Erstellen einer Collage. Zuerst ein leeres Dokument erzeugen, auf dem alle anderen Bilder zusammengefügt werden sollen (über [Datei] > [Neu])

Modellbildungssysteme: Pädagogische und didaktische Ziele

LU-Zerlegung. Zusätze zum Gelben Rechenbuch. Peter Furlan. Verlag Martina Furlan. Inhaltsverzeichnis. 1 Definitionen.

S/W mit PhotoLine. Inhaltsverzeichnis. PhotoLine

Mediator 9 - Lernprogramm

A Lösungen zu Einführungsaufgaben zu QueueTraffic

Betragsgleichungen und die Methode der Fallunterscheidungen

1.Unterschied: Die Übungen sind nicht von deinem Mathe-Lehrer...

4. BEZIEHUNGEN ZWISCHEN TABELLEN

Das sogenannte Beamen ist auch in EEP möglich ohne das Zusatzprogramm Beamer. Zwar etwas umständlicher aber es funktioniert

Grundbegriffe der Informatik

Mobile Intranet in Unternehmen

Grundlagen der höheren Mathematik Einige Hinweise zum Lösen von Gleichungen

Enigmail Konfiguration

Anleitung über den Umgang mit Schildern

Lösung. Prüfungsteil 1: Aufgabe 1

Doku zur Gebäudebrüter Datenbank

Einführung in. Logische Schaltungen

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Inhalt. Allgemeine Einführung. Argumentationsvermögen. Räumliches Vorstellungsvermögen. Begabungen und Fähigkeiten messen

Kontakte Dorfstrasse 143 CH Kilchberg Telefon 01 / Telefax 01 / info@hp-engineering.com

1. Man schreibe die folgenden Aussagen jeweils in einen normalen Satz um. Zum Beispiel kann man die Aussage:

Alle Schlüssel-Karten (blaue Rückseite) werden den Schlüssel-Farben nach sortiert und in vier getrennte Stapel mit der Bildseite nach oben gelegt.

Arbeiten mit UMLed und Delphi

5 DATEN Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu

Lineare Funktionen. 1 Proportionale Funktionen Definition Eigenschaften Steigungsdreieck 3

Lineare Gleichungssysteme

Überblick. Lineares Suchen

Die Größe von Flächen vergleichen

R ist freie Software und kann von der Website.

FuxMedia Programm im Netzwerk einrichten am Beispiel von Windows 7

mysql - Clients MySQL - Abfragen eine serverbasierenden Datenbank

Programmieren in C. Rekursive Funktionen. Prof. Dr. Nikolaus Wulff

L10N-Manager 3. Netzwerktreffen der Hochschulübersetzer/i nnen Mannheim 10. Mai 2016

Softwarelösungen: Versuch 4

Projektmanagement in der Spieleentwicklung

Persönliche Zukunftsplanung mit Menschen, denen nicht zugetraut wird, dass sie für sich selbst sprechen können Von Susanne Göbel und Josef Ströbl

Typdeklarationen. Es gibt in Haskell bereits primitive Typen:

Das große ElterngeldPlus 1x1. Alles über das ElterngeldPlus. Wer kann ElterngeldPlus beantragen? ElterngeldPlus verstehen ein paar einleitende Fakten

Simulation LIF5000. Abbildung 1

FAQ Spielvorbereitung Startspieler: Wer ist Startspieler?

geben. Die Wahrscheinlichkeit von 100% ist hier demnach nur der Gehen wir einmal davon aus, dass die von uns angenommenen

Kreativ visualisieren

Approximation durch Taylorpolynome

Übung Theoretische Grundlagen

Abschluss Version 1.0

Transkript:

Kapitel 7 Parallele Berechnungen 7.1 Teile und Herrsche (Divide and Conquer) Diese Entwurfsmethode für Algorithmen ist in vielen Bereichen nützlich und lässt sich folgendermaßen beschreiben: Teile das Problem in kleinere gleichartige Unterprobleme (Divide) Löse rekursiv die entstehenden Unterprobleme (Conquer) Setze die Lösungen zusammen. Einige Instanzen haben wir schon kennengelernt: Mergesort: Die Liste wurde in zwei gleichlange Unterlisten zerlegt. Quicksort. Die Liste wurde in zwei Unterlisten, der kleineren und größeren Elemente zerlegt. Intervallhalbierung: Das Intervall wurde in zwei Hälften zerlegt. Das Zusammensetzen der Lösung war nicht nötig. Die schnelle Berechnung ganzzahliger Potenzen. Algorithmen auf Baumstrukturen Die Methode Teile-und-Herrsche kann zur Parallelisierung von Algorithmen eingesetzt werden. Auch in sequentiellen Anwendungen kann man teilweise Laufzeitanteile O(n) zu einer Laufzeit in O(log(n)) verbessern. Für sequentielle und parallele Algorithmen gilt: Der Aufwand des Teilens und Zusammenfügens darf nicht zu groß sein, da sonst keine Verbesserung eintritt. Ebenso sollte die Gesamtsumme der Größen der Teilprobleme höchstens die Größe des Problems selbst haben. Zum Beispiel ist die Laufzeit des Einfügesort O(n 2 ), während der Merge-Sort Laufzeit O(n log(n)) hat. 1

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 2 Beispiel 7.1.1 Wir betrachten das Beispiel der Türme von Hanoi zur Demonstration des Divide-and-conquer Verfahrens. Gegeben ist ein Stapel von verschieden großen Goldscheiben, wobei die Goldscheiben von oben nach unten größer werden. Die Aufgabe ist, diesen Stapel auf einen zweiten umzustapeln, wobei man einen weiteren Hilfsstapel verwenden darf, aber nur kleine auf größeren Scheiben liegen dürfen. Nach der Sage war dieser Stapel 64 Scheiben hoch, und wenn die Aufgabe gelöst ist, dann ist das Ende der Zeit gekommen. Die Berechnung der notwendigen Umstapelungen lässt sich leicht mit der Teile-und-Herrsche Methode zerlegen: 1 n-1 n 2 n n-1 3 n-1 n Man erhält: Die Bewegungen für n, die notwendig sind: 1. Bewegungen, die notwendig sind, um einen n 1 Stapel von 1 nach 3 umzustapeln, wobei 2 der Hilfsstapel ist. 2. Bewege die Scheibe n von Stapel 1 nach Stapel 2 3. Bewegungen, die notwendig sind, um den n 1 Stapel von 3 nach 2 umzustapeln, wobei 1 der Hilfsstapel ist. Wenn man die Nr. der Stapel als Variable mitführt, so erhält man einen recht einfachen Algorithmus dafür, wenn man bei der rekursiven Lösung der Teilprobleme die unteren Scheiben ignoriert. Das Ergebnis ist eine Liste (von Bewegungen) der Länge 2 n 1, wenn n die Anzahl der Scheiben ist.

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 3 -- hanoi gibt Zugfolge aus, die zum Ziel f\"uhrt: -- Scheiben-groesse, von-stapel, zu-stapel -- hanoi: Stapel, Stapelnr, Zielstapelnr Hilfstapelnr hanoi xs a b c = hanoiw (reverse xs) a b c hanoiw [] _ = [] hanoiw xa a b c = (hanoiw (tail xa) a c b) ++ ((head xa,(a,b)) : (hanoiw (tail xa) c b a)) -- Testaufruf und Ergebnis: -- hanoi [1,2,3] 1 2 3 -- [(1,(1,2)), (2,(1,3)), (1,(2,3)), (3,(1,2)), (1,(3,1)), -- (2,(3,2)), (1,(1,2))] In der Programmdatei befindet sich ein Interpreter (in zwei Varianten), der die Aktionen ausführt. 7.2 Parallele Algorithmen und deren Ressourcenbedarf 7.2.1 Parallele und verteilte Berechnungen Parallele, nebenläufige, konkurrierende und verteilte Berechnungen bzw Prozesse erfordern i.a. das Zusammenwirken verschiedener Computer oder Prozessoreinheiten. Bei den Berechnungen der Effizienz der Parallelisierung in der Praxis spielen die Kosten / Zeitverbrauch für die Kommunikation und Latenz (Verzögerungszeiten) eine Rolle, die in theoretische Betrachtungen oft nicht eingehen. Es gibt grundverschiedene Modellvorstellungen dieser Berechnungen: Klassifikation der parallelen Rechnerarchitekturen von Flynn, die sich auf parallele Instruktionssequenzen und Parallelität der Verarbeitung von Daten bezieht: SISD: Single instruction, single data stream (SISD) : Sequentieller Rechner ohne Parallelität. MISD:Multiple instruction, single data stream : kommt so gut wie nicht vor: Man könnte redundante (Doppel-) Verarbeitung hier einordnen.

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 4 Verar- SIMD: Single instruction, multiple data streams Gleiche beitung. viele gleichartige Daten: z.b. Vektorprozessor. MIMD:Multiple instruction, multiple data streams Mehrere Prozessoren lassen verschiedene Programme auf verschiedenen Daten ablaufen: Verteilte Systeme. PRAM Mehrere Prozessoren haben einen gemeinsamen Hauptspeicher und können unabhängig lesen und schreiben (PRAM: parallel random access machine) und bearbeiten eine gemeinsame Aufgabe. Bei Untersuchungen unterscheidet wegen des Problems des gleichzeitigen Zugriffs von verschiedenen Prozessoren auf die gleiche Speicheradresse, auch danach, ob Lese- und/oder Schreibzugriffe exklusiv oder konkurrierend sind (EREW, CRCW, CREW, (E = Exklusiv, C = concurrent, R 0 Read, W = Write)). Diese Unterscheidung wird eher in theoretischen Betrachtungen verwendet. Im Endeffekt unterscheiden sich diese Varianten nicht sehr, da man diese umkodieren kann. Verteilt, lose Kopplung Mehrere unabhängige Rechner kommunizieren über ein Netzwerk und arbeiten gemeinsam an einer Berechnung. Die verwendeten Programme bzw Programmteile können völlig verschieden sein. Hier unterscheidet man zum Teil nach der Art der Kommunikation (synchronisierte / nicht synchronisiert) und danach wie die Topologie der Prozessoren oder der Prozesse ist: Gleichberechtigt, sternförmig, hierarchisch (Master/ Slave) bzw. (Client / Server). Zum Beispiel PVM ist ein System, das mehrere Rechner zu einer gemeinsamen Rechnung auf mehrere Arten zusammenschließen kann. Ein weiteres Beispiel ist Grid-Computing, bei dem viele Rechner, i.a. PCs, gemeinsam an einer Aufgabe rechnen, i.a. alle Rechner das gleiche Programm verwenden, aber andere Daten bearbeiten. massiv parallel, enge Kopplung Sehr viele unabhängige Rechner sind über ein schnelles Netzwerk gekoppelt und arbeiten gemeinsam an einer Berechnung. Hier werden tendenziell eher die Daten verteilt und das Programm bzw. der Programmkode auf den Knoten ist identisch bzw. vor der Berechnung bereits den Knoten bekannt. Beispiele: Hyperwürfel und ähnliche Netzwerke, Hardware für künstliche neuronale Netze. Vektorrechner, Feldrechner Hier gibt es ein Programm, das gleichzeitig auf viele Daten angewendet wird. Sinnvoller Einsatz: Wettersimulationen, numerische Berechnungen. Diesen Typ bezeichnet man auch als SIMD (single instruction, multiple data) Pipelining Hier ist meist die parallele Ausführung von Maschinenkode auf der Hardware eines Prozessor gemeint. Das Pipelining beschleunigt diese Ausführung zunächst dadurch, dass die Befehlsbearbeitung in kleinere Einheiten zerlegt wird, die dann nacheinander abgearbeitet werden, so

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 5 dass mehrere Maschinenbefehle quasi parallel abgearbeitet werden. Durch Mehrfachauslegung von internen Einheiten kann man das noch weiter beschleunigen. 7.2.2 Maße für den Ressourcenverbrauch Für die folgenden Betrachtungen nehmen wir an, dass wir eine Programmiersprache und eine operationale Semantik haben, so dass folgende Begriffe sinnvoll definiert sind: Ein (sequentieller) Einzelschritt einer Programmauswertung (bzgl eines Interpreters) Ein paralleler Einzelschritt, der sich aus mehreren unabhängigen Einzelschritten zusammensetzt, normalerweise an verschiedenen Stellen im Programm. Hierbei bauen wir auf das PRAM-Modell: ein gemeinsamer Hauptspeicher, das Programm bzw die Programmteile greifen immer auf denselben Hauptspeicher zu. Die Befehlsabarbeitung ist synchron getaktet. Wie die parallelen Schritte ausgeführt werden, ist in diesem Zusammenhang nicht so wichtig. Um die Anzahl der Prozessoren in der Rechnung zu berücksichtigen, nehmen wir an, dass pro Einzelschritt einer parallelen Auswertung ein Prozessor notwendig ist. Weiterhin muss man natürlich annehmen, dass die Prozessoren nicht unterscheidbar sind, d.h. alle die gleiche Arbeit leisten können. Schaut man genauer hin, so haben wir hier eigentlich auch von den Prozessoren selbst abstrahiert und zählen nur die Einzel-Auswertungsschritte. Zusammenfassend kann man sagen: Die gleichzeitige Durchführung einer Menge von unabhängigen Auswertungseinzelschritten ist ein paralleler Auswertungsschritt. Die Anzahl dieser parallelen Schritte bis zu einem Ergebnis ist dann die Anzahl der parallelen Reduktionsschritte. Die maximale Anzahl gleichzeitiger Einzelauswertungsschritte in einem parallelen Schritt entspricht der Anzahl der notwendigen Prozessoren. Definition 7.2.1 Die Parallelisierung ist konservativ, wenn nur Reduktionen durchgeführt werden, die für das Erreichen des Resultats notwendig sind. Die Parallelisierung ist spekulativ, wenn auch Reduktionen durchgeführt werden können, von denen zum Zeitpunkt der Ausführung nicht bekannt ist, ob diese für das Berechnen des Resultats notwendig sind. Beispiel 7.2.2 Die normale Reihenfolge der Auswertung in Haskell macht nur notwendige Reduktionen und berechnet einen Wert, wenn es eine Reduktion zu einem Wert gibt. Die parallele Reduktion von s und t in einem Ausdruck

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 6 if cond then s else t führt i.a. überflüssige Reduktion durch. Allerdings kann man die notwendigen von den redundanten erst dann unterscheiden, wenn cond berechnet wurde. Sei ein Algorithmus in der gewählten Programmiersprache gegeben, sei E die jeweilige Eingabe, und p die maximale Anzahl der aktiven Prozessoren. Wir nehmen an, dass die Auswertung getaktet erfolgt. Ein einzelner Reduktionsschritt benötigt eine Zeiteinheit auf einem Prozessor. Man darf p Reduktionsschritt in einer Zeiteinheit machen, wenn diese parallel ausführbar sind und wenn p Prozessoren erlaubt sind. Das ist dann ein paralleler Reduktionsschritt. Wir definieren: τ(e, p) parallele Zeit ist die minimale Anzahl der parallelen Reduktionsschritte bis zum Ergebnis, τ(e, 1) sequentielle Zeit ist die Anzahl der Einzel-Reduktionsschritte wenn es nur einen Prozessor gibt, d.h. bei sequentieller Auswertung. τ(e, ) optimale parallele Zeit ist die Anzahl der parallelen Reduktionsschritte bis zum Ergebnis, wenn es keine obere Schranke für die Anzahl der Prozessoren gibt. Als Optimist würde man erwarten, dass bei optimalem Programmieren die τ(e, 1) Berechnung um den Faktor p beschleunigt wird. D.h. τ(e, p), was p leider eher selten der Fall ist. Wir nehmen im folgenden (zunächst ) der Einfachheit halber an, dass die Kennzahlen nur vom Algorithmus und proportional zur jeweiligen Eingabe E sind, d.h. wir können τ(p) einführen mit τ(e, p) E τ(p), so dass wir uns nicht um die Schwankungen kümmern müssen; zudem können wir die Eingabegröße E in den Formeln dann oft wegkürzen. Den Faktor τ(1) nennt man (relative) parallele Beschleunigung. τ(p) Die parallele Beschleunigung ist eine Zahl zwischen 1 und p, und gibt den Faktor an, um den eine Berechnung durch Parallelisierung beschleunigt wird. Diese Zahl kann nicht kleiner als 1 sein in unserem Modell, da stets eine Reduktion möglich ist. Sie kann aber auch nicht größer als p sein, denn eine parallele Reduktion zu einem Ergebnis kann man sequentiell nachvollziehen. τ(1) Den Faktor nennt man parallele Effizienz. Dies ist der Anteil der p τ(p) für den Algorithmus nutzbaren gesamten Prozessorleistung.

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 7 Ein illustratives Beispiel der Laufzeiten und Werte könnte so aussehen: τ(1) τ(3) τ(4) parallele Zeit 1000 500 400 parallele Beschleunigung 1 2 2,5 parallele Effizienz 1 66,6% 62,5% Die parallele Effizienz ist eine Zahl zwischen 1 und 1/p. 1 ist das Optimum und zeigt an, dass alle Prozessoren zur Berechnung beitragen. 1/p bedeutet, dass die Berechnung im wesentlichen sequentiell ist und nur einen Prozessor auslasten kann. Prinzip: Ist für eine Anzahl p von Prozessoren die parallele Effizienz =1, dann gilt das im wesentlichen auch für kleinere Anzahlen von Prozessoren. Denn man kann die parallelen Reduktionen ja auf einer kleineren Anzahl von Prozessoren ebenfalls ausführen, nur etwas sequentialisierter. Den Faktor τ(1) τ( ) kann man auch darstellen als lim p nennt man maximale parallele Beschleunigung. Den τ(1) τ(p). Die maximale parallele Beschleunigung ist der Wert, den man erhält, wenn man eine unbeschränkte Anzahl von Prozessoren hat. Diesen Wert kann man als obere Schranke einer praktisch erreichbaren parallelen Beschleunigung ansehen. Wenn die maximale parallele Beschleunigung q ist, dann kann man den sequentiellen Anteil der zur Berechnung benötigten Zeit ausdrücken als: 1/q. Die Anzahl w(p) (die verrichtete Arbeit (work)), sei die minimale Anzahl von Einzel-Reduktionsschritten aller parallelen Reduktionen, die ein Ergebnis berechnen. Für w(p) gilt stets: w(p) τ(1), die sequentielle Zeit. I.a. ist für einen optimal parallel beschleunigten Algorithmus die insgesamt verrichtete Anzahl der Einzel-Auswertungen höher als für den besten sequentiellen Algorithmus. Ein Maß für die mittlere Anzahl beschäftigter Prozessoren lässt sich berechnen als w(p) w(p). Die Zahl, könnte man die mittlere Auslastung τ(p) p τ(p) nennen. 7.2.3 Amdahls Gesetz Amdahls Gesetz sagt ewtas aus zur Begrenzung der parallelen Beschleunigung unter bestimmten Annahmen. Man nimmt an, dass die Gesamtzeit T, die zur Berechnung eines Problems gebraucht wird, unabhängig von der Größe des Problems, in einen sequentiellen Anteil und einen parallelisierbaren Anteil zerlegbar ist: T = T par + T seq

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 8. Wobei der prozentuale Anteil (asymptotisch) konstant wird. Das kann man dadurch rechtfertigen, dass man in Algorithmen Datenabhängigkeiten hat, oder sequentielle Anteile erkennt. Z.B. ist bei der parallelen Verarbeitung eines Baumes zumindest der Abstieg zu den Blättern sequentiell, d.h. die Tiefe des Baumes bestimmt eine Untergrenze des sequentiellen Anteils. Die Beschleunigung durch p Prozessoren kann man dann beschreiben als T par + T seq (1/p) T par + T seq Lässt man unendlich viele Prozessoren zu, dann erhält man: parallele Beschleunigung T par + T seq T seq Bei einem sequentiellen Anteil von 5% kann man somit keine bessere Beschleunigung als Faktor 20 erwarten. Man beachte aber, dass Amdahls Gesetz unter der Annahme gilt, dass die Eingabe bzw. die Größe der Eingabe keinen Einfluß auf den sequentiellen Anteil der Berechnung hat. 7.2.4 Gustafson-Barsis Gesetz Hier ist die Annahme, dass die Zeit T zur Berechnung auf einem Prozessor sich gemäß T = T seq +T par berechnen lässt, wobei T seq ein fester sequentiellen Anteil, z.b. Initialisierung ist und T par eine auf Prozessoren verteilbare Berechnungszeit ist. Zudem wird angenommen, dass beliebig viele Prozessoren zur Verfügung stehen. Man betrachtet somit einen optimal parallelisierbaren Fall. Ein weitere Annahme ist, dass es ein kleinste Zeiteinheit T p gitb, die sich sinnvoll auf einem einzigen Prozessor ausführen lässt: Dann definiert man α = T seq T p, und da man beliebig viele Prozessoren hat, braucht man im konkreten Fall gerade soviel, dass T = T seq + p T p ist. Das ergibt: parallel Beschleunigung = T seq + p T p T seq + T p = α + p α + 1 Diese ist unbegrenzt im Gegensatz zu Amdahls Annahmen. Der Lerneffekt ist, dass man bei der Parallelisierung auch analysiert, ob bei größer werdenden Problemeingaben auch der parallelisierbare Anteil mitwächst. Beispiel 7.2.3 Betrachtet man als Beispiel die Anwendung einer Funktion f auf alle Arrayelemente eines Arrays der Länge n, dann ist T seq die Initialisierungszeit und T p die Zeit zum Berechnen der Anwendung f x. Wenn diese Zeiten in etwa gleich groß sind, ergibt sich für die Beschleunigung mit n Prozessoren die Beziehung: 1 + n. 2

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 9 7.2.5 Algorithmen und Parallelisierung in Haskell In diesem Abschnitt betrachten wir parallele Verarbeitung auf der Auswertungsebene in Haskell. Um für ein gegebenes Programm in einer eingeschränkten Haskell- Kernsprache Aussagen machen zu können über maximale Beschleunigung, den Bedarf einer Berechnung an Anzahl Prozessoren u. ä., verwenden wir als vereinfachtes Modell die verzögerte Auswertung (lazy evaluation) für Haskell mit Sharing, wobei wir erlauben, dass unabhängige Transformationsschritte parallel durchgeführt werden dürfen. Um dies formal korrekt durchzuführen, stellen wir uns vor, dass Haskell-Ausdrücke als let-ausdrücke vorliegen (In einer Implementierung können wir auch annehmen dass es markierte gerichtete Graphen sind), so dass Transformationen als Veränderungen in dem Ausdruck (in dem Graphen) angesehen werden können. Hierbei müssen wir festlegen, was ein Transformationseinzelschritt ist: Dies sind β-reduktionen, eine case-reduktionen oder arithmetischen Auswertungen zu den Funktion (+,,, >. <,,,...). Wir zählen let-reduktionen nicht. Wir zählen auch die Transformation nicht, die ein Kompiler benötigt um z.b. Listen-Komprehensionen oder Pattern-Matching weg zu transformieren. Wir gehen also davon aus, dass Listenkomprehensionen in expandierter Form, d.h. als Ausdrücke unter Benutzung von map, filter, concat vorliegen. Analog zum Ressourcenbedarf geben wir auch hier asymptotischen Abschätzungen der Laufzeit mit der O-Notation an. Beispiel 7.2.4 quadratsumme 3 4 (3*3)+(4*4) 9+16 25. Der zweite Reduktionsschritt ist ein paralleler Reduktionsschritt, der aus 2 Einzelreduktionen besteht. Insgesamt sind es drei parallele Reduktionen bei 4 sequentiellen Reduktionsschritten. Die Beschleunigung ist nur moderat. fakt 3 if 3 == 1 then 1 else 3*(fakt (3-1)) if False then 1 else 3*(if 2 == 1 then 1 else 2*(fakt (2-1) ) 3*(if False then 1 else 2*(if 1 == 1 then 1 else 1*(fakt (1-1))) 3*(2*(if True then 1 else 1*(if 0 == 1 then 1 else 1*(fakt0))) 3*(2*(1)) 3*(2) 6 Dies sind 7 parallele Auswertungsschritte bei maximal 4 gleichzeitigen Transformationen. Man sieht (Übungsaufgabe), dass diese Anzahl linear in n ist. D.h. selbst durch massiven Einsatz von vielen Prozessoren lässt sich dieser Algorithmus nicht wesentlich beschleunigen. Es ist nicht schwer, ein Haskellprogramm für Fakultät zu schreiben, das bei paralleler Auswertung die Fakultät von n mit O(log(n)) Multiplikationen berechnet, d.h. in Zeit O(log(n)), wenn man die Größe der Zahlen als fest ansieht.

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 10 Da bei der Fakultätsfunktion die Anzahl der Stellen eine Rolle spielt. muss man diese bei der echten Laufzeit berücksichtigen: Die Anzahl der Stellen ist von der Größenordnung O(n!), d.h. O(nlog(n)), ergibt sich O(n 2 log(n)) beim sequentiellen Algorithmus O(nlog 2 (n)) beim parallelen Algorithmus, wenn man annimmt, dass Multiplikation in konstanter Zeit möglich ist. Es kann vorkommen, dass in diesem parallelen Modell unnötige Transformationen gemacht werden. Wenn wir uns für den geringstmöglichen Bedarf (bzw. für eine untere Grenze) der parallelen Reduktionsschritten (Zeit) interessieren, dann ist unser Modell zur einfachen Berechnung dieser Zahl geeignet. Wenn wir allerdings die Anzahl der parallel möglichen Transformationen beschränken wollen, da z.b. nur eine feste Anzahl an Prozessoren zur Verfügung steht, dann ist das eine schwerere Aufgabe, da wir über viele mögliche parallele Reduktionsfolgen minimieren müssen. Wir betrachten hier nur die maximal mögliche Parallelität und die schnellstmögliche Verarbeitung. Hierzu haben wir im Modell auch eine Vereinfachung gemacht: die Vernachlässigung der Kommunikation und der Handhabung der Ausdrücke, d.h. wir vernachlässigen die Zeit zur Suche nach den Reduktionsmöglichkeiten, die Zeit zur Ersetzung der Ausdrücke und die Zeit für Reorganisation des gerichteten Graphen. Beispiel 7.2.5 Betrachte den Ausdruck map quadrat [1..n]. Dieser Ausdruck evaluiert nach folgendem Schema: map quadrat [1..n] 1: map quadrat [2..n] 1: 4: (map quadrat [3..n]) Man sieht, dass dies auch bei beliebiger unabhängiger Transformation O(n) parallele Reduktionsschritte benötigt. D.h. dieser Algorithmus lässt sich analog zum normalen Algorithmus für Fakultät nicht durch parallele Auswertung beschleunigen. Bei Optimierung bzgl. paralleler Auswertung muss man beachten, dass die Anzahl der sequentiellen Abhängigkeiten gering bleibt und dass man andere Algorithmen schreiben muss, die besser für parallele Auswertung geeignet sind. Man sieht auch, dass Listenverarbeitung in dieser Form sich durch Parallelisierung nicht richtig beschleunigen lässt, da man die Listen immer von vorne nach hinten abarbeiten muss. Eine wesentliche Verbesserung bieten baumartige Datenstrukturen. Beispiel 7.2.6 Wir betrachten verschiedene Algorithmen zur Summation von n Zahlen. Wenn die n Zahlen in einer Liste gegeben sind, dann kann man den Algorithmus sum nehmen: sum [] = 0 sum (x:xs) = x+ (sum xs)

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 11 sum[n, n 1,..., 1] ergibt n β-schritte, einen Schritt sum[], und n Summationen. Dies sind 2 n + 1 Schritte, d.h. O(n) Reduktionsschritte. Wir nehmen an, dass die Zahlen in einem balancierten binären Baum gegeben sind. Dann nehmen wir folgenden Algorithmus: sumbt (Bblatt x) = x sumbt (Bknoten bl br) = (sumbt bl) + (sumbt br) Das ergibt für einen binären Baum der Tiefe h, wenn ein Blatt die Tiefe 0 hat: 2 (h + 1) Schritte, d.h., da der Baum balanciert ist, weniger als log 2 (n) + 1 Schritte, d.h. dieser parallele Algorithmus benötigt eine logarithmische Anzahl von parallelen Transformationen. Dieser Algorithmus ist damit viel besser für parallele Verarbeitung geeignet als der erste. Schnelles Fold über Bäume: Man erkennt jetzt die Problematik: Wenn man nur eine sequentielle Auswertungsmaschine hat, dann ist das foldbt die schnellste Methode. Wenn allerdings parallele Auswertung möglich ist, dann ist das fold besser, das die Struktur des Baumes berücksichtigt. Beispiel 7.2.7 Paralleles Sortieren von (verschiedenen) Zahlen. Wir wollen hier nur ein Beispielproblem vorführen und zeigen, dass man parallel wesentlich schneller sortieren kann als sequentiell. Nehme an, dass die Zahlen als ein balancierter binärer Baum eingegeben werden. Die Idee dieses Algorithmus ist die parallele Ermittlung der Rangfolge einer Zahl in der Folge der sortierten Zahlen. csnrtop bb = csnr bb bb csnr (Bblatt x) bb = Bblatt (x,sumbt (snr x bb)) csnr (Bknoten bl br) bb = Bknoten (csnr bl bb) (csnr br bb) -- zaehlt die kleineren snr x (Bblatt y) = Bblatt (if y <= x then 1 else 0) snr x (Bknoten bl br) = Bknoten (snr x bl) (snr x br) Wir versuchen für diesen Algorithmus die parallele Laufzeit abzuschätzen. Sei h die Tiefe des binären Baumes. 1. csnr benötigt von oben bis zu einem Blatt h parallele ReduktionsSchritte. 2. Danach braucht die Auswertung von snr innerhalb des sumbt-ausdrucks h Schritte. 3. sumbt benötigt ebenfalls h parallele Reduktionsschritte. In der Summe ergibt dies O(h) Schritte. In Abhängigkeit von n, der Anzahl der Zahlen am Anfang, ergibt dies eine Größenordnung von O(log(n)). Wollte man als Ergebnis eine Liste erzeugen, dann benötigt man zum sequentiellen

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 12 Erzeugen der Liste n Reduktionsschritte. Man kann aber mit parallelen Reduktionen in Zeit O(log(n)) einen binären Baum erzeugen, der von links nach rechts sortiert ist. Eine parallele Erzeugung der Liste sortierter Zahlen aus einem links-rechts geordneten binären Baum funktioniert mit folgendem Algorithmus: -- Umbau in einen sortierten Baum gen_sbaum bb = case gen_sbaumw bb 1 (csanzahl bb) of Just x -> x -- Dieses Funktion erzeugt einen Suchbaum -- mittels divide und conquer gen_sbaumw (Bblatt (x,nr)) von bis = if von <= nr && nr <= bis then Just (Bblatt x) else Nothing gen_sbaumw topbaum@(bknoten bl br) von bis = if von == bis then case gen_sbaumw br von bis of Just baum -> Just baum Nothing -> gen_sbaumw bl von bis else let mitte = (von+bis) div 2 in if von +1 == bis then gen_sbaumw_comb (gen_sbaumw topbaum von von) (gen_sbaumw topbaum bis bis) else gen_sbaumw_comb (gen_sbaumw topbaum von mitte) (gen_sbaumw topbaum (mitte+1) bis) -- Kombination der Ergebnisse gen_sbaumw_comb Nothing Nothing = Nothing gen_sbaumw_comb (Just x) Nothing = Just x gen_sbaumw_comb Nothing (Just x) = Just x gen_sbaumw_comb (Just bl) (Just br) = Just (Bknoten bl br) csanzahl (Bblatt _) = 1 csanzahl (Bknoten bl br) = (csanzahl bl) + (csanzahl br) Hier die parallele (logarithmische) Erzeugung einer Liste aus einem Baum.

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 13 slgen (Bblatt x) = [x] slgen (Bknoten bl br) = slinksgen bl (slgen br) slinksgen (Bblatt x) tail = x: tail slinksgen (Bknoten ubl ubr) tail = slinksgen ubl (slinksgen ubr tail) -- test_sortbaum = (Bknoten (Bknoten (Bblatt 8) (Bblatt 7)) (Bknoten (Bblatt 6) (Bblatt 5))) -- test_sort2 = slgen (gen_sbaum (csnrtop test_sortbaum)) Dieser Algorithmus aus slgen und slinksgen erzeugt bei paralleler Auswertung die sortierte Liste in Zeit O(log(n)): Die Argumentation: slgen kann unabhängig von rest bis zur Tiefe des Baumes auswerten. slinksgen erzeugt zwei unabhängige zu reduzierende Ausdrücke, die ebenfalls die Tiefe um eins reduzieren. Mit Induktion sieht man: Nur die Tiefe des Baumes bestimmt die Anzahl der parallele Reduktionsschritte. Damit haben wir als parallelen Zeitbedarf des Sortierens mit dem oben angegebenen Algorithmus: O(log(n)), wenn n Zahlen als Blätter in einem balancierten Baum gegeben sind. Dies ergibt dann auch eine obere Schranke des parallelen Zeitbedarf des Sortierens. Im allgemeinen ist man aber mit der Erzeugung eines Suchbaumes besser bedient als mit der Erzeugung einer sortierten Liste. Wir ermitteln dazu noch die anderen Zahlen zum Ressourcenbedarf: Die parallele Beschleunigung ist, wenn wir etwas lax rechnen: O(n log(n)/log(n)). D.h. wir erhalten eine lineare Beschleunigung. Um die parallele Effizienz zu ermitteln, benötigt man die Anzahl der Prozessoren, die maximal gleichzeitig beschäftigt sind, bzw. die maximale Anzahl gleichzeitiger Reduktionsschritte. Diese maximale Anzahl wird in der Funktion csnr erreicht. Es wird für jedes Blatt des Baumes über eine Kopie des Baumes addiert. Dies erfordert im schlechtesten Fall n n Prozessoren. Die parallele Effizienz ergibt sich dann zu c/n. D.h. die Nutzung der Prozessoren ist ziemlich schlecht. Den exakten Gesamtaufwand an Reduktionen zu berechnen sei dem Leser überlassen. Hier soll eine Schätzung versucht werden: Die Summation ergibt c 1 n n für das Summieren; c 2 n log(n) log(n) für den Umbau des Baumes, und c 3 n log(n) für das Erzeugen der Liste. Der quadratische Term überwiegt asymptotisch. Also ergibt sich O(n 2 ). Wenn man nur n Prozessoren zur Verfügung hat, besteht bereits die Gefahr, dass der parallele Algorithmus schlechter wird als ein guter sequentieller Sortieralgorithmus. Das Beste was man dann noch erwarten kann, ist ein linearer Algorithmus, da die Gesamtanzahl an Reduktion O(n n) ist. Fazit: Sortieren kann durch Parallelisierung wesentlich beschleunigt werden.

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 14 Beispiel 7.2.8 Parallelisierung des Bubble-Sort. Wir stellen uns dies als ein Array der Länge n vor. Die Prozessoren sollen so operieren, dass benachbarte Feldinhalte vertauscht werden, wenn die Zahlen in falscher Reihenfolge sind. Dafür genügen n 1 Prozessoren. Wenn man noch vereinbart, dass die Prozessoren immer abwechselnd operieren, d.h. im ersten Schritt 1,3,5,7,..., im zweiten Schritt 2,4,6,.... Dann ergibt sich, dass nach n Schritten das Feld sortiert ist. Dies ist nicht ganz so einfach zu verifizieren, aber es stimmt: siehe in der Literatur unter odd-even transposition sort. Betrachtet man die Maßzahlen, dann erhält man: parallele Beschleunigung: log(n)). parallele Effizienz: log(n)/n Gesamtanzahl an Operationen: n n D.h. man kann mit n Prozessoren tatsächlich mit dieser Methode einen einfachen Sortieralgorithmus angeben. Beispiel 7.2.9 Die Suche nach einem Element in einem Suchbaum lässt sich durch Parallelisierung nicht beschleunigen. Denn der Baum muss von oben nach unten durchlaufen werden. D.h. die Verarbeitung braucht mindestens soviele Schritte, wie die Höhe des Baumes. Gedankenexperiment: Wir versuchen, die Suche nach einem Element in konstanter Zeit durchzuführen. Die Idee: Wir verteilen (ordnen zu) die n Zahlen jeweils auf einen Prozessor. Wenn eine bestimmtes Element gesucht wird, dann schauen alle Prozessoren gleichzeitig nach, und vergleichen. Der Prozessor, der die Antwort findet, ruft: ja. Die beschriebenen Verarbeitungsschritte sind tatsächlich in konstanter Zeit machbar, allerdings zeigt ein Versuch, dies konkreter zu programmieren, dass die Modellvorstellung die Wirklichkeit nicht ganz trifft: 1. Wie kommen die n Zahlen in ihren jeweiligen Prozessor? 2. Wie erhalten die Prozessoren den gesuchten Wert? 3. Wie wird die Antwort ermittelt? Dazu betrachten wir als Modell einen zentralen Rechners und mehrere Sklaven-Rechner der die Anfrage hat und das Ergebnis benötigt. 1. Man benötigt das Senden eines Vektors an adressierte Rechner: Wenn alle Rechner mit allen verbunden sind, so kann der Aufbau der Nachrichten schon ein lineares Problem darstellen. 2. Zum Versenden der Zahl benötigt man ein Senden an alle (sogenanntes broadcast). Wenn alle Rechner mit allen verbunden sind, so ist es technisch denkbar, dass dies in konstanter Zeit abläuft. Wenn dies nicht der Fall ist, so geht die Anzahl der Vermittlungen ein. Nimmt man eine obere Grenze für die Anzahl der direkt verbundenen Rechner, so geht dieser Vermittlungsaufwand logarithmisch ein.

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 15 3. Die Antworten müssen gesammelt und ausgewertet werden. Nimmt man an, dass nur die positive Antwort versendet wird, dann ist das zwar maximal eine Nachricht, aber im Falle dass keine Nachricht kommt, ist unklar, welche Zeit man abwarten muss, bis das nein wirklich klar ist. Sendet und empfängt man man alle Antworten, dann ist der Empfangsaufwand hoch. Wir betrachten mal das PRAM-Modell mit gemeinsamen Speicher. Um konstante Zeit beim Suchen zu erreichen, kann man den gesuchten Wert im Speicher allen zur Verfügung stellen. Die Prozessoren müssen aber verschieden sein, bzw. Ihren Aufgabenbereich kennen. Der einfachste Fall ergibt sich, wenn jeder Prozessor genau einen Wert kennt, d.h. wenn der Suchbaum vorher entsprechend aufgeteilt wurde. Ein Prozessor gibt nur dann eine Antwort, wenn er den gefragten Wert hat. Die Antowrt wird an einem vorher vereinbarten Speicheradresse abgelegt. Der Masterprozessor muss jetzt wissen, wie lange die Antowrt maixmal dauert, und kann dann auch eine negative Antwort erkennen. Wenn der gefragte Wert die Prozessoren in konstanter Zeit erreicht, dann ist das Problem in Zeit O(1) lösbar. Technisch ist dann trotzdem ein logarithmischer Faktor notwendig, da nicht alle gleichzeitig das Feld lesen können, es muss eine Verteilung (broadcasting) in stattfinden. Bemerkung 7.2.10 Teile-und Herrsche ist offenbar ein Verfahren, bei dem man recht gute parallele Algorithmen erhalten kann. Die Algorithmen, die zeitlinear sind und eine Liste mehrfach durchlaufen, erweisen sich oft als ungeeignet zur Parallelisierung. Bisher haben wir keine Rücksicht darauf genommen, ob die Transformationen auch wirklich notwendig waren, d.h. wir haben ohne Rücksicht auf Kosten alles parallel ausgewertet. Diese Methode heißt auch spekulative Parallelisierung. Diese Methode erweist sich leider in praktischen Versuchen als hoffnungslos, da i.a. die Anzahl der nutzlosen Transformationen nach kurzer Zeit bei weitem die der nützlichen überwiegt. Außerdem steigt der Platzbedarf oft sehr stark. D.h. die Ausdrücke blähen sich an unerwarteten Stellen stark auf. Operational ist dann meist nicht festzustellen, wo die relevanten Ausdrücke sind. Versucht man, nur solche Unterausdrücke zu transformieren, die für das Endergebnis notwendig sind, so ergibt sich das Dilemma, dass man diese Unterausdrücke nicht definitiv ermitteln kann. Man kann eine (operationale) Methode angeben, die konservativ parallel reduziert, indem man folgende Markierungsstrategie verwendet: die oberste Ebene des Ausdruck ist als transformierbar markiert Wenn op s t als zu reduzieren markiert ist, dann auch s, t, wenn op ein arithmetischer (eingebauter) Operator ist.

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 16 Analog kann man verfahren mit Funktionen, von denen man zur Kompilierzeit ermitteln kann, dass die parallele Auswertung der Argumente garantiert konservativ ist Wenn der Ausdruck if b then s 1 else s 2 als reduzierbar markiert ist, und b nicht schon True oder False ist, dann markiere auch b. Diese Markierungsstrategie kann zur Kompilierzeit vorbereitet werden und bestimmt, welche Auswertungen zur Laufzeit tatsächlich gestartet werden. Dies ergibt eine (parallele) Transformationsstrategie, die genausoviel Reduktionen ausführt wie die normale Reihenfolge der Auswertung, aber möglicherweise nicht immer die parallele Zeit optimiert. Dieses Verfahren ist schon nahe an einer guten Parallelisierung. Allerdings mussman für eine reale parallele Maschine beachten, dass diese meist eine feste Anzahl an Prozessoren hat. Das große praktische Problem ist die gute Verteilung der Arbeitseinheiten auf diese Prozessoren. Ein weiteres Problem sind die möglicherweise zu kleinen Arbeitseinheiten. Wenn die angeforderte Anzahl an Auswertungen die der Prozessoren übersteigt, dann ist es schwer, automatisch die Prioritäten so zu setzen, dass die wichtigen Reduktionen zuerst kommen. Es kann sein, dass zu viele Auswertungsanforderungen die Speicherverwaltung überlasten, weil zu weit vorgegriffen wurde. Beispiel 7.2.11 Als Beispiel betrachte man die Aufgabe, in einem großen sequentiellen Text-File die Anzahl der Vorkommen des Zeichens e zu ermitteln. Angenommen, der File passt als Baum oder Feld in den Hauptspeicher. Parallel ergibt dies soviele Reduktionen, wie der File Zeichen enthält. Da erst die (parallele) Addition alles wieder aufsammelt und den Platz freigibt, kann es im schlimmsten Fall dazu kommen, dass die Auswertung stecken bleibt, weil kein Platz mehr vorhanden ist. Mischt man parallele und sequentielle Reduktion, dann hat man, praktisch gesehen, eher eine Chance, mit weniger Platzanforderung, die Rechnung zu Ende zu bringen und die mögliche Parallelität zu nutzen. Betrachtet man andere Programmiersprachen, so ist diese Parallelisierung, die wir betrachtet haben, eine implizite Parallelisierung, d.h analog zu einer vom Compiler berechneten parallelisierten Ausführung. Da hier ein praktisch befriedigendes Verhalten nur selten erreicht wird, erlaubt man i.a. explizite Parallelisierung, d.h es gibt explizit parallele Befehle. Z.B.: Führe eine Operation auf allen Elementen eines Feldes aus (paralleles map). Das parallele Skalarprodukt: n a i b i ist oft eine parallelisierte Basisfunktion. i=1 Bemerkung 7.2.12 Das praktische Problem der parallelen Algorithmen ist, dass im Moment die technische Entwicklung der Beschleunigung der sequentiellen Rechner nach einer gewissen Zeit die parallelen Architekturen wieder einholt.

Grundlagen der Programmierung 2, SS 2005, Kapitel 5, vom 14. Dezember 2004 17 Da die Architekturen für parallele Rechner sehr unterschiedlich sind, ist es i.a. sehr aufwändig, Anwendungsprogramme zu entwickeln, die den Zeitvorteil nutzen können. D.h. Parallelisierung und/oder verteilte Berechnung eines einzelnen Problems lohnt sich nach heutigem Stand der Technik nur in wenigen Fällen: Die Aufgabe ist von Hand in viele gleichartige größere Stücke zu zerlegen und kann auf andere Rechner verteilt werden: Z.B. Faktorzerlegung einer Primzahl. (grobkörniger Parallelismus, Datenparallelismus) Die Parallelität ist im Programm unsichtbar oder sehr kontrolliert einsetzbar und wird von der Maschine / dem Kompiler hinzugefügt. Eine wichtige Anwendung mit vielen gleichartigen kleinen Berechnungen lohnt den Aufwand, massiv parallele Systeme einzusetzen. (Simulationen, Wetter,... ) (sogenannter feinkörniger Parallelismus) Diese Situation könnte sich in Zukunft wieder ändern. Supercomputer mit den besten Benchmarks sind Parallelrechner, wobei der Spitzenreiter 131.072 Prozessoren hat. Um das auszunutzen, braucht man leicht parallelisierbare Probleme, bei denen man z.b. gleichartige Array-operationen bzw. Matrizenoperationen usw. auf verschiedenen Prozessoren ausführen kann. 7.2.6 Ein Ausflug in die Komplexitätstheorie Wir schauen uns eine theoretische Einteilung von Problemen bzgl. ihrer Parallelisierbarkeit an. Es gibt eine Komplexitätsklasse von Entscheidungs-Problemen, die man als NC ( Nick s Class ) (Nikolaus Pippenger) bezeichnet und die die Klasse der effizient parallelisierbaren Probleme charakterisiert. Es sind die Probleme, die man in polylogarithmischer Zeit, d.h. O(log c (n)) für ein c > 0 mit polynomiell vielen Prozessoren bearbeiten kann. Das ist nicht realistisch, da das bedeutet, dass man bei n Eingaben z.b. n oder sogar n 2 Prozessoren zur Verfügung haben müsste. Die Klasse P T ime aller Probleme, die in polynomieller Zeit bearbeitet (bzw. entschieden) werden können, enthält diese Klasse. Man geht davon aus, dass diese Untermengenbeziehung echt ist. Dadurch ist es manchmal möglich, nachzuweisen, dass man eine Problemklasse nicht auf diese günstige Weise parallelisieren kann. Beispiel 7.2.13 für ein Problem das in NC ist: Die Summation von n Zahlen, die in einem balancierten Baum (oder Array) gegeben sind: man darf n Prozessoren verwenden, muss einmal in Zeit O(log(n)) bis an die Blätter, und muss dann die Ergebnisse wieder in Zeit log(n) (parallel) addieren. Sind die Zahlen beschränkt und die arithmetischen Operationen in konstanter Zeit möglich, dann kann man die Aufgabe inn Zeit O(log(n)) mit n Prozessoren durchführen.