Threads oder Prozesse

Zur Parallelisierung einer Software kann man auf Threads und Prozesse zugreifen. Es lohnt sich, diese beiden Ansätze etwas genauer anzuschauen, um die geeignete Wahl treffen zu können.

Warum Parallelisierung?

  • Mehr CPUs nutzen
  • Moore’s law: Anzahl der Transistoren in IC verdoppelt sich ca. alle 2 Jahre.
  • Bis vor ca. 10 Jahren verdoppelte sich die CPU-Leistung auch regelmäßig.
  • Seit ca. 10 Jahren nur noch mehr Cores
  • Nur nutzbar durch Parallelisierung
  • Parallelisierung kann aber auch Dinge vereinfachen.
  • Beispiel Pipes:
cat `find /usr/bin/* -type d -prune -o -type f -print` \
| perl -p -e 's/sch/\\v s/g;s/\r/\n/g;' | strings \
| sort > /tmp/out.log &
  • Startet pro Pipe-Komponente einen Prozess, viel flexibler und meist perfomanter als wenn man Zwischenergebnisse in Dateien zwischenspeichern muss.
  • Integration verschiedener Software-Komponenten.
  • Typische Beispiele:
    • Datenbank
    • Messaging-System
    • SAP
    • Heterogene Software (mehrere Programmiersprachen…)

Probleme bei Parallelisierung

Unabhängig von der verwendeten Technologie muss man sich mit u.a. diesen Problemen auseinandersetzen:

  • Deadlocks (Verklemmung)
  • Fehler bei gleichzeitigem Ressourcenzugriff
  • Overhead der Parallelisierung
  • Erschwerte Fehlersuche

Deadlocks

Beispiel für Deadlock:

  • Zwei parallel laufende Programmteile A und B greifen exklusiv auf zwei Ressourcen X und Y zu.
  • A reserviert sich erst X und dann Y, B reserviert sich erst Y und dann X.
  • Bei ungünstigem Verlauf wartet A endlos auf Y und B endlos auf X.

Fehler bei gleichzeitigem Ressourcenzugriff

  • Beispiel Datenstruktur wird von Programmteil A und Programmteil B gleichzeitig verwendet.
  • Wenn beide Zugriffe nur lesend sind, ist das ok.
  • Wenn einer schreibt, kann es Inkonsistenzen geben, wegen Pointern sogar Programmabstürze, merkwürdige Fehler u.s.w.
  • Schwierig zu finden
  • Tritt oft erst auf dem Produktivsystem auf, beim Testen scheint alles gut zu sein.

Overhead

Wenn man Software parallelisiert muss man zusätzlich Dinge tun, die man sonst nicht braucht:

  • Locking
  • Kommunikation
  • Synchronisation
  • Memory
  • Mehr Entwicklungsaufwand

Das kann sich aber lohnen.
Besser frühzeitig daran denken!!!

Wie zähmt man die Parallelisierung?

  • In Applikationsentwicklung mit geeigneten Werkzeugen, Frameworks,…
  • In der Praxis viele Probleme und oft wenig Gewinn
  • Aber es gibt Wege die funktionieren..
  • Traum: Compiler parallelisiert automatisch
  • Aber für Systemprogrammierung explizite Kontrolle wichtig!

Threads oder Prozesse

Threads oder Prozesse???

Man kann für die Parallelisierung drei Wege gehen (oder Kombinationen daraus):

  • Prozesse
  • Threads auf OS-level
  • Eigener Mechanismus (User Threads)

Prozesse

  • Prozesse haben ihren eigenen Speicherbereich
  • Können auf verschiedenen Rechnern laufen
  • Explizite Kommunikation
  • Mit shared memory kann man auch gemeinsamen Speicher nutzen
  • Mehr Overhead als Threads

Threads

  • Threads laufen auf derselben Maschine
  • Teilen sich dasselbe Memory
  • Trennung muss man explizit erzwingen

Funktionsweise Prozess (POSIX)

  • Ein neuer Prozess wird mit fork() erzeugt
  • Dupliziert den ganzen Speicher
  • Effizient wegen copy-on-write
  • Achtung: overcommit
  • Danach (meistens) exec

Unter MS-Windows wird das Erzeugen eines neuen Prozesses und das Starten eines neuen Programms gleichzeitig in einem Schritt ausgeführt.

IPC

Interprozesskommunikation:

  • Signale
  • Pipe (named oder anonym)
  • Semaphore (Locks)
  • Shared Memory
  • Socket
  • Message Queue
  • File
  • Memory-mapped File
  • High-Level-Mechanismen (DB, Messaging, Corba, Rest, Soap, RPC,…)

Threads (Posix)

  • Mit pthread_create(…) erzeugen
  • Mit pthread_join(…) “einsammeln”
  • Funktion void *f(void *) übergeben
  • In C++ 11 in die Sprache integriert

Was soll man bevorzugen

Es hängt von der Ausgangslage ab.

Entwickelt man mit Ruby oder Perl, sind vielleicht mehrere Prozesse besser, weil Threads in diesen Sprachen nicht so gut unterstützt werden. Entwickelt man mit Scala oder Java, sind Threads vielleicht besser, weil das dort das gängige und gut unterstützte Parallelisierungsverfahren ist und weil JVM-Prozesse jeweils recht schwergewichtig sind, was den Speicherverbrauch betrifft.

Entwickelt man in C oder C++ und hat mehr oder weniger alle Möglichkeiten des Betriebssystems zur Verfügung, dann sind beide Wege gut gangbar. Man kann mit Shared Memory und anderen IPC-Mechanismen mehrere Prozesse zusammenspannen, aber auch mehrere Threads. Man muss sich in jedem Fall darum kümmern, dass gemeinsam genutzte Ressourcen konsistent bleiben und insbesondere nicht in inkonsistentem Zustand gelesen werden.

Man sollte beide Möglichkeiten kennen und im Einzelfall entscheiden, welcher Weg sich am besten eignet.

Share Button

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*