Multicore-Programmierung im .NET-Umfeld – Teil 3

veröffentlicht von Michael Hülskötter am 2. Februar 2009

Nach den Teilen eins und zwei folgt heute der dritte Abschnitt unserer Mini-Serie “Multicore-Programmierung im .NET-Umfeld”. Es geht um Tasks und Futures, um das Parallelisieren von Methoden, um parallele Schleifen, um einen Taskmanager und um PLINQ.

Tasks sind die zentralen Elemente der Parallel Extensions, also dedizierte Aufgaben, Funktionen, Schleifenkonstrukte oder ähnliche Dinge. Eine Task führt stets eine Funktion oder ein anderes Konstrukt innerhalb eines Threads aus, um so eine optimale Ausnutzung der Systemressourcen zu erzielen.

Das Besondere daran sind die Call-Back-Funktionen, die es ermöglichen, bestimmte Dinge zu übergeben, die in einem separaten Thread ausgeführt werden sollen. Mithilfe der Tasks müssen Anwendungsprogrammierer also nicht mehr in Threads denken, da diese von den .NET-Tools automatisch erzeugt, verwaltet und auf die vorhandenen Ressourcen verteilt werden.

Daneben gibt es Futures, also Tasks mit Rückgabewerten. Solch ein Future-Konstrukt führt beispielsweise in einem eigenen Task eine Funktion aus, deren Ergebnis an das Hauptprogramm übergeben wird, das währenddessen weiterrechnen kann. Zwar muss das Programm an einer bestimmten Stelle auf das Ergebnis warten, kann aber trotzdem parallel andere Aufgaben ausführen. Eine weitere simultane Ausführungsoption ist die Methode Parallel_Invoke(), die einen ganzen Satz von Methoden zugleich abarbeiten kann, sofern diese voneinander unabhängig sind.

Aber auch Schleifenkonstrukte bieten sich für die parallele Programmierung an, da hier gerechnet wird, was mithilfe einer parallelen Ausführung erheblich beschleunigt werden kann. Der große Vorteil von parallelen Schleifenkonstrukten ist deren fehlende Abhängigkeit von globalen oder lokalen Variablen, die bei der sequenziellen Ausführung entstehen. Ebnenso eignet sich der parallele Datenzugriff (beispielsweise bei Datenbankanwendungen) sich bestens zum Parallelisieren.

Als Beispiel dient eine Matrixoperation, die mit drei Variablen arbeitet, die bei der sequenziellen Programmierung mithilfe eines dreifach-verschalteten Schleifenkonstrukts das Ergebnis der Matrixberechnung ermittelt. Bei der parallelen Schleife Parallel.For() hingegen wird nur die äußere Schleife initiiert, die zwei inneren Schleifen werden per Methode übergeben. Im Hintergrund werden dann die zwei “inneren Schleifen” auf zwei parallele Threads verteilt. Die Daten werden dann am Schluss automatisch zusammengeführt. Und so sieht der Quellcode dazu aus:

Matrixoperation mithilfe der Parallel.For-MethodeEine weitere Kernfunktion des .NET-4.0-Frameworks ist die Taksmanager-Klasse, die sich um die optimale Auslastung der Systemressourcen, sprich Prozessoren und CPU-Kerne, kümmert. Hierfür versucht der Taskmanager stets, die notwendigen WorkerThreads gleichmäßig mit Tasks zu bestücken. Das geht sogar so weit, dass “unterbeschäftigte” WorkerThreads einzelne Tasks von “überbeschäftigten” WorkerThreads erhalten, um so ein optimal ausgelastetes System zu garantieren. Die Strategie dahinter nennt sich “Work Stealing”. Der Taskmanager ist übrigens beliebig konfigurierbar und ermittelt unter anderem die vorhandene Anzahl an Prozessoren.

Aber nicht nur die Parallelisierung von Berechnungen, sondern auch der simultane Datenzugriff wird bei .NET 4.0 im Vordergrund stehen. Hierfür wird die seit .NET 3.5 verfügbare Spracherweiterung LINQ (Language Integrated Query) parallelisiert, woraus PLINQ entsteht. Mit PLINQ kann man typsicher auf bestimmte Behälterklassen zugreifen, also auf Arrays, Listen, Queues oder Hashtabellen. Diese Datenzugriffe erinnern an die Abfragekonstrukte von relationalen Datenbanken.

Mit SQL-ähnlichen Abfragen und Konstrukten lässt sich beispielsweise möglichst schnell und simultan nach einem bestimmten Namen suchen. Dies gilt zumindest für große Datensätze. Sind nämlich nur wenigen Daten vorhanden, entpuppt sich die Parallelisierung oft als kontraproduktiv, da der notwendige Overhead die Berechnung eher ausbremst als beschleunigt.

Mit der Methode AsParallel() können in großen Datensätze simultan nach bestimmten Daten gesucht werden


Share/Bookmark
Kategorien : Multicore Tags : , ,

Kommentare
Beitrag kommentieren.

Sie müssen angemeldet sein um diesen Beitrag zu kommentieren. [Login | Registrieren]

(erforderlich)

(erforderlich)