Parallele Programmierung: Pythons Multiprocessing-Modul vs. PLINQ

Entwicklern stehen zahlreiche Tools zur Verfügung, die die parallele Programmierung erleichtern und Programme so beschleunigen sollen. Nicht alles ist für jeden Zweck geeignet, aber häufig lohnt der Einsatz eines entsprechenden Werkzeugs.

vorlesen Druckansicht 11 Kommentare lesen
Lesezeit: 19 Min.
Von
  • Vladimir Poliakov
Inhaltsverzeichnis

Entwicklern stehen zahlreiche Tools zur Verfügung, die die parallele Programmierung erleichtern und Programme so beschleunigen sollen. Nicht alles ist für jeden Zweck geeignet, aber häufig lohnt der Einsatz eines entsprechenden Werkzeugs.

Die Multicore-Architektur findet man heutzutage nicht nur auf Supercomputern, sondern auch im Haushalt. Ein Dual-Core Prozessor auf dem Smartphone ist zum minimalen De-facto-Standard dieser Geräteklasse geworden. Um die Vorteile der Architektur zu nutzen, sollte man sich mit paralleler Programmierung auseinandersetzen. Der vorliegende Praxisbericht demonstriert einige Möglichkeiten dieser Technik und kann als Ansatzpunkt für eigene Experimente dienen.

Die Aufgabe im vorliegenden Fall ist es, die Ergebnisse der Analyse der Oracle TNSLISTENER-Log-Dateien darzustellen. Dazu ist geplant, die unstrukturierten Daten mit dem MapReduce-Entwurfmuster abzuarbeiten. Als Werkzeuge sollen sequenzielle Verarbeitung in der Linux-Shell, das Modul multiprocessing aus Python auf Linux und Windows, Hadoop Streaming auf dem Linux Single Server, die C# Microsoft Task Parallel Library (TPL) und PLINQ auf Windows zum Einsatz kommen.

Die Berechnungen der später aufgeführten Ergebnisse fanden auf zwei physischen Linux-Servern und einem virtuellen Windows-Server mit mehreren Prozessoren statt. Der dazu verwendete Programmcode ist nicht allzu kompliziert und für diejenigen Entwickler interessant, die das MapReduce-Verfahren kennenlernen und einsetzen möchten. Im Idealfall sollte man zum Verständnis über Grundkenntnisse in Python und .NET. verfügen. Kenntnisse der parallelen Programmierung sind hingegen nicht zwingend erforderlich.

Der Bericht vergleicht die sequenzielle und parallele Verarbeitung und zeigt die benötigte Zeit pro eingesetzter Technik (Python vs. PLINQ), Betriebssystem (Linux vs. Windows) und Prozessortyp (physische Server vs. VMWare Server).

Das Oracle-Datenbanksystem ist eine komplexe Datenbank-Software und verfügt über mehrere Komponenten, die unterschiedliche Log-Dateien schreiben. Eine der wichtigsten Komponenten ist TNSLISTENER. Sie ist für die Kommunikation zwischen den Oracle Clients und dem Datenbankserver zuständig. TNSLISTENER schreibt die Log-Einträge im Text und im XML-Format. Ab Version 11.2.0.2 lassen sich die XML-Dateien zwar mit SQL auswerten, aber um die unnötige Last auf dem Produktionsdatenbankserver zu vermeiden und die Multicore-Architektur testen zu können, wurde die 20 GByte große Log-Datei für das Experiment in kleine Teile zerstückelt und auf die anderen Server übertragen. Abbildung 1 zeigt das Format der TNSLISTENER-Einträge:

Die Datei TNSLISTENER.LOG enthält die Kommunikationen zwischen Clients und Datenbanken. (Abb. 1)

Die geplante Analyse der Log-Datei sollte die Anzahl der Verbindungen je Programm und Client ermitteln (siehe Abbildung 2). FĂĽr diese Aufgabe eignet sich das MapReduce-Verfahren vergleichsweise gut, das in Python und C# implementiert wurde.

Die Analyse der TNSLISTENER.LOG-Datei zeigt die hergestellten Verbindungen an. (Abb. 2)

Bereits 2004 hat Google das MapReduce-Programmiermodell präsentiert. Es findet normalerweise bei Berechnungen mit großen Datenmengen auf Computerclustern Verwendung, ist allerdings auch anderweitig einsetzbar und lässt sich beispielsweise im kleinen Maßstab auf einem Multicore-Server nutzen. Bei dem Verfahren werden die Daten in den drei Phasen Map, Shuffle und Reduce verarbeitet, wobei Entwickler Map und Reduce selbst spezifizieren.

In der Map-Phase bildet der Algorithmus eine Liste von Paaren, die jeweils aus einem Schlüssel und einem Wert bestehen. Während der Shuffle-Phase sortiert das Programm die Zwischenergebnisse und/oder tauscht die Ergebnisse zwischen den Servern im Cluster. Das Summieren der Zwischenergebnisse und Erstellen einer Liste mit Endergebnissen (ähnlich wie auf der Abbildung 2) findet in der Reduce-Phase statt. Map- und Reduce-Funktion werden idealerweise parallel ausgeführt. Abbildung 3 zeigt das MapReduce-Muster, das im behandelten Fall tatsächlich zum Einsatz kam.

MapReduce lässt sich auf unterschiedliche Weisen umsetzen. (Abb. 3)

Die einzelnen, parallel ausgeführten Reduce-Phasen waren nötig, um die Datenmenge nach der Map-Phase noch weiter zu reduzieren. Ohne diese Schritte lief die Berechnung in eine Out-of-Memory Exception. Außerdem hat das Verkleinern der Log-Dateien zur Verbesserung der Performance beigetragen. Beides ist später noch einmal Thema.