Artikel

 
Oktober 2009 | Artikel

GPars: Parallelität für Java mit Groovy-Mitteln

(Link zum Artikel: http://www.it-republik.de/jaxenter/artikel/2608)

Text: Dierk König
  • Teilen
  • kommentieren
  • empfehlen
  • Bookmark and Share
Es scheint eine allgemein akzeptierte Unterstellung zu sein, dass wir zukünftig keine relevanten Verbesserungen der Prozessorgeschwindigkeit mehr sehen werden, dafür aber ein exponentielles Wachstum der Anzahl an Rechenkernen. Nehmen wir einmal an, das sei der Fall.

Heißt das nun, dass wir zukünftig massiv parallele Programme schreiben müssen? Hier scheiden sich schon die Geister. Die einen nehmen die "Multicore-Era" zum Anlass, für neue Programmiersprachen zu werben. Andere – wie Brian Goetz (Autor des Bestsellers "Java Concurrency in Practice") auf der letzten JavaOne – bezweifeln das und plädieren für verbesserte Frameworks.

Diesen Ansatz verfolgt auch das GPars-Projekt (Groovy Parallel Systems). Wie oft bei Groovy-Frameworks handelt es sich um eine dünne Schicht, die vereinfachten Zugang zu den mächtigen Möglichkeiten von Java bietet. Der Java-Programmierer bleibt in seiner gewohnten Umgebung, bekommt aber neue Abstraktionen, mit denen er Parallelität in seinen Programmen leichter und mit mehr Sicherheit gestalten kann. Zu den neuen Abstraktionen gehören:

  • Aktoren (auch verteilte)
  • Datenflussoperatoren
  • Sicherungen für veränderliche Objekte (Safe) sowie
  • nebenläufige Operationen auf Collections und
  • asynchrone Ausführungen

Die Implementierungen stützen sich auf das java.util.concurrent-Paket und deren Konzepte, aber auch auf Java-Sprachelemente wie volatile und synchronized. Zusätzlich kommt das Fork-/Join-Konzept aus dem JSR 166 zum Einsatz. Groovy wird vor allem für das API-Design verwendet. Wer mag, kann auch "DSL"dazu sagen. Groovy-Eigenschaften wie @Immutable oder collection.asImmutable() sind natürlich zusätzlich hilfreich. Die Skalierbarkeitseigenschaften sind sehr kompetitiv. Ganz ohne JVM-Tricks kann man Millionen von Aktoren oder Datenflussvariablen verwenden.

GPars ist darauf ausgelegt, in Java-Projekten mit Java Code – und dem JDK – zusammen verwendet zu werden. Das ist ein großer Unterschied zu den Ansätzen, die zwar Aufrufe von Java erlauben, in dem Fall aber mit ihren eigenen Konzepten brechen. Mein Lieblingsbeispiel: Verwendung von Seiteneffekten wie System.out.println(), z. B. in einem Aktor.

Für die klassischen Probleme der nebenläufigen Programmierung wie Sleeping Barber oder Dining Philosophers enthält das GPars-Projekt mehr als 60 Demos, die sich weder in Lesbarkeit noch in Funktionalität hinter anderen Ansätzen verstecken müssen. Im Gegenteil, viele Lösungen sind einfach beispielhaft schön.

Wer GPars einsetzen will, kann sich entweder das jar herunterladen, das Maven-Projekt referenzieren, die Plug-ins für Grails und Griffon installieren oder die Groovy @Grab-Annotation verwenden, mit der alle abhängigen jars automatisch aus dem Maven Repository geladen, zwischengespeichert und in den Klassenpfad aufgenommen werden. Das folgende Groovy Script funktioniert also selbst ohne GPars-Installation. Es bearbeitet eine Instanz von java.util.List nebenläufig auf zwei Arten: Zuerst werden die Quadratzahlen nebenläufig berechnet und das Ergebnis als Liste zurückgegeben. Das ist ein Beispiel für transparentes Fork/Join. Zweitens wird jedes Element der Liste getrennt bearbeitet, das Quadrat berechnet und ausgegeben. Die Reihenfolge der Ausgabe ist absichtlich nicht vorhersehbar, es ist aber gesichert, dass nachdem die eachAsync-Methode beendet ist, auch alle Ausgaben erfolgt sind:

  1. // requires Groovy 1.6
  2. import org.gparallelizer.Parallelizer
  3. @Grab(group='org.gparallelizer', module='gparallelizer', version='0.8.4')
  4. List getList() { (1..9).toList() }
  5. Parallelizer.withParallelizer {
  6. println list.collectAsync { it * 2 }
  7. list.eachAsync { print it * 2 + ' ' }
  8. }

Eine mögliche Ausgabe kann so aussehen:

  1. [2, 4, 6, 8, 10, 12, 14, 16, 18]
  2. 10 12 2 4 8 14 16 18 6

Letzteres funktioniert nur deshalb korrekt, weil die print-Methode von java.io.PrintStream intern auf sich selbst synchronisiert und so vermischte Ausgaben verhindert. Das ist Java-Entwicklerwissen, das man benötigt, ganz unabhängig davon, mit welcher Sprache man auf der JVM programmiert, und Groovy versucht auch nicht, das zu verbergen.

Wichtig ist, dass der Beipielcode mit jeder beliebigen Instanz von java.util.List arbeiten kann, auch wenn sie aus Code stammt, der in Java geschrieben wurde oder aus externen Bibliotheken stammt. Bei der Bearbeitung kann man wiederum auf beliebige Java/Groovy-Objekte zugreifen.

GPars war bis zur Version 0.8.4 noch bei Google-Code als "GParallelizer" gehosted, ist aber jetzt zu Codehaus umgezogen, wurde umbenannt und hat auch seine Paketstruktur auf groovyx.gpars umgestellt. Das API wird sich bis zur Version 1.0 noch weiter entwickeln. Die Arbeit geht zügig voran und wer sich daran beteiligen will, ist herzlich willkommen.

Alle enthaltenen Konzepte, ihre Implementierung und ihren Einsatz zu beschreiben, benötigt etwas mehr Platz als ein Kurzbeitrag bietet. Die Onlinedokumentation und die apidoc geben schon einen guten Überblick, müssen aber noch vervollständigt werden. Hilfreich sind in meinen Augen vor allem die Demos. Weitere Publikationen zum Thema sind in Planung – so wird auch die zweite Auflage von "Groovy in Action" GPars in einem Kapitel beschreiben.

Dierk König ist Softwareentwickler und Coach bei Canoo Engineering AG, Basel. Er betreibt das Open-Source-Projekt Canoo WebTest und ist Committer in den Projekten Groovy und Grails. Er publiziert zu den Themen Extreme Programming, Testing und Rich Internet Applications. Er ist Autor des Buchs "Groovy in Action". Twitter: @mittie
  1. http://gpars.codehaus.org
  2. www.manning.com/koenig2
  3. http://groovy.codehaus.org


Anzeige

Kommentare


Anzeige

zurück zum Seitenanfang