Freigeben über


Concurrency Runtime im Vergleich zu anderen Parallelitätsmodellen

In diesem Dokument werden die Unterschiede zwischen den Funktionen und Programmiermodellen der Concurrency Runtime und von anderen Technologien beschrieben. Durch das Abwägen der Vorteile der Concurrency Runtime und anderer Programmiermodelle können Sie die Technologie wählen, die den Anforderungen Ihrer Anwendungen am besten entspricht.

Wenn Sie derzeit ein anderes Programmiermodell, z. B. den Windows-Threadpool oder OpenMP, verwenden, können Situationen eintreten, in denen es eventuell sinnvoll ist, zur Concurrency Runtime zu migrieren. Beispielsweise wird im Thema Migrieren von OpenMP zur Concurrency Runtime beschrieben, wann es sinnvoll sein kann, von OpenMP zur Concurrency Runtime zu migrieren. Wenn Sie jedoch mit der Anwendungsleistung und der aktuellen Debugunterstützung zufrieden sind, ist keine Migration erforderlich.

Sie können die Funktionen und Produktivitätsvorteile der Concurrency Runtime verwenden, um Ihre vorhandene Anwendung, die ein anderes Parallelitätsmodell verwendet, zu ergänzen. Die Concurrency Runtime kann keinen Lastenausgleich sicherstellen, wenn mehrere Taskplaner um dieselben Computerressourcen konkurrieren. Dies hat jedoch minimale Auswirkungen, solange sich Arbeitslasten nicht überschneiden.

Abschnitte

  • Vergleich von präemptiver Planung mit kooperativer Planung

  • Vergleich der Concurrency Runtime mit der Windows-API

  • Vergleich der Concurrency Runtime mit OpenMP

Vergleich von präemptiver Planung mit kooperativer Planung

Das präemptive Modell und kooperative Planungsmodelle sind zwei häufig verwendete Möglichkeiten, um dafür zu sorgen, dass Computerressourcen wie beispielsweise Prozessoren oder Hardwarethreads von mehreren Aufgaben gemeinsam genutzt werden können.

Präemptive und kooperative Planung

Präemptive Planung ist ein zyklischer, prioritätsbasierter Mechanismus, durch den jeder Aufgabe für einen bestimmten Zeitraum exklusiver Zugriff auf eine Computerressource gewährt wird und anschließend der Wechsel zu einer anderen Aufgabe erfolgt. Präemptive Planung ist bei Multitasking-Betriebssystemen wie Windows üblich. Kooperative Planung ist ein Mechanismus, durch den jeder Aufgabe so lange exklusiver Zugriff auf eine Computerressource gewährt wird, bis die Aufgabe beendet ist oder sie den Zugriff auf die Ressource abgetreten hat. Die Concurrency Runtime verwendet kooperative Planung zusammen mit dem präemptiven Planer des Betriebssystems, um eine maximale Nutzung der Verarbeitungsressourcen zu erreichen.

Unterschiede zwischen präemptiven und kooperativen Planern

Präemptive Planer versuchen, mehreren Threads gleichwertigen Zugriff auf Computerressourcen zu gewähren, damit jeder Thread Fortschritte machen kann. Auf Computern mit vielen Computerressourcen lässt sich leichter dafür sorgen, dass der Zugriff fair gestaltet wird. Andererseits ist es problematischer, eine effiziente Auslastung der Ressourcen zu gewährleisten.

Bei einem präemptiven Kernelmodusplaner ist es erforderlich, dass sich der Anwendungscode bei Planungsentscheidungen auf das Betriebssystem verlässt. Im umgekehrten Fall kann Anwendungscode durch einen kooperativen Planer im Benutzermodus eigene Planungsentscheidungen treffen. Da durch kooperative Planung viele Planungsentscheidungen von der Anwendung getroffen werden, wird der Aufwand beträchtlich reduziert, der mit Kernelmodussynchronisierung in Verbindung gebracht wird. Ein kooperativer Planer richtet sich in der Regel bei Planungsentscheidungen nach dem Betriebssystem-Kernel, wenn keine andere Arbeit zu planen ist. Ein kooperativer Planer richtet sich auch nach dem Betriebssystemplaner, wenn ein blockierender Vorgang vorhanden ist, der zwar dem Kernel, aber nicht dem Benutzermodusplaner mitgeteilt wird. Unter Betriebssystemen, von denen diese UMS-Threads (User-mode Schedulable) unterstützt werden, werden diese blockierenden Vorgänge vom Concurrency Runtime-Planer in kooperative blockierende Vorgänge konvertiert.

Kooperative Planung und Effizienz

Für einen präemptiven Planer ist sämtliche Arbeit, die über dieselbe Prioritätsstufe verfügt, gleich. Ein präemptiver Planer plant Threads gewöhnlich in der Reihenfolge, in der sie erstellt werden. Darüber hinaus gewährt ein präemptiver Planer jedem Thread basierend auf der Thread-Priorität auf zyklische Weise einen Zeitanteil. Obwohl durch diesen Mechanismus für Fairness gesorgt wird (jeder Thread macht Fortschritt), leidet die Effizienz etwas darunter. Für viele berechnungsintensive Algorithmen ist beispielsweise keine Fairness erforderlich. Stattdessen ist es wichtig, dass verwandte Aufgaben insgesamt so schnell wie möglich ausgeführt werden. Durch kooperative Planung kann eine Anwendung Arbeit effizienter planen. Denken Sie beispielsweise an eine Anwendung mit zahlreichen Threads. Plant man Threads, die keine gleichzeitig auszuführenden Ressourcen nutzen, lässt sich der Synchronisierungsaufwand reduzieren und somit die Effizienz steigern. Eine andere effiziente Möglichkeit der Aufgabenplanung ist es, Pipelines von Aufgaben (wobei jede einzelne Aufgabe basierend auf der Ausgabe der vorherigen Aufgabe handelt) auf demselben Prozessor auszuführen, damit die Eingabe jeder Pipelinephase bereits in den Arbeitsspeichercache geladen ist.

Gemeinsames Verwenden von präemptiver und kooperativer Planung

Durch kooperative Planung lassen sich nicht alle Planungsprobleme lösen. Beispielsweise können alle verfügbaren Computerressourcen von Aufgaben genutzt werden, die anderen Aufgaben gegenüber nicht in angemessenem Maß zurücktreten. Dadurch können andere Aufgaben keinen Fortschritt machen. Die Concurrency Runtime nutzt die Effizienzvorteile der kooperativen Planung, um die Fairnessgarantien der präemptiven Planung zu komplementieren. Die Concurrency Runtime bietet standardmäßig einen kooperativen Planer, der die Arbeit mithilfe eines Arbeitsübernahme-Algorithmus effizient zwischen Computerressourcen verteilt. Der Concurrency Runtime-Planer ist jedoch auch auf den präemptiven Planer des Betriebssystems angewiesen, um Ressourcen gerecht auf Anwendungen zu verteilen. Sie können in den Anwendungen auch benutzerdefinierte Planer und Planerrichtlinien erstellen, um die Threadausführung präzise zu steuern.

[Nach oben]

Vergleich der Concurrency Runtime mit der Windows-API

Die Microsoft Windows-Anwendungsprogrammierschnittstelle, die in der Regel als Windows-API (und früher als Win32) bezeichnet wird, stellt ein Programmiermodell bereit, mit dem in den Anwendungen Parallelität möglich ist. Die Concurrency Runtime stellt basierend auf der Windows-API zusätzliche Programmiermodelle zur Verfügung, die auf dem zugrunde liegenden Betriebssystem nicht vorhanden sind.

Die Concurrency Runtime nutzt das Windows-API-Threadmodell beim Ausführen paralleler Arbeit. Es verwendet auch die Windows-API-Speicherverwaltung und lokale Threadspeichermechanismen. Unter Windows 7 und Windows Server 2008 R2 verwendet es Windows-API-Unterstützung für UMS-Threads und Computer, die mehr als 64 Hardwarethreads aufweisen. Die Concurrency Runtime erweitert das Windows-API-Modell, indem ein kooperativer Taskplaner und ein Arbeit stehlender Algorithmus bereitgestellt werden, um die Nutzung von Computerressourcen zu maximieren, und indem mehrere gleichzeitige Planerinstanzen möglich sind.

Weitere Informationen zur Windows-API finden Sie unter Übersicht über die Windows-API.

Programmiersprachen

Die Windows-API macht das Programmiermodell mithilfe der Programmiersprache C verfügbar. Die Concurrency Runtime stellt eine C++-Programmierungsschnittstelle bereit, die die neuesten Funktionen der Programmiersprache C++ nutzt. Lambdafunktionen stellen z. B. einen knappen, typsicheren Mechanismus bereit zum Definieren von parallelen Arbeitsfunktionen. Weitere Informationen zu den neuesten C++-Funktionen, die von der Concurrency Runtime genutzt werden, finden Sie unter Übersicht über die Concurrency Runtime.

Threads und Threadpools

Der zentrale Parallelitätsmechanismus in der Windows-API ist der Thread. Zum Erstellen von Threads wird gewöhnlich die CreateThread-Funktion verwendet. Obwohl sich Threads relativ leicht erstellen und verwenden lassen, weist das Betriebssystem eine beträchtliche Menge an Zeit und anderen Ressourcen zu, um sie zu verwalten. Darüber hinaus sind aufgrund des damit verbundenen Aufwands ausreichend große Aufgaben zu erstellen, obwohl für jeden Thread garantiert wird, dass er die gleiche Ausführungszeit erhält wie ein beliebiger anderer Thread auf gleicher Prioritätsstufe. Für kleinere oder differenziertere Aufgaben kann der Aufwand, der mit der Parallelität in Verbindung steht, größer sein als der Vorteil, den das parallele Ausführen von Aufgaben mit sich bringt.

Threadpools sind eine Möglichkeit, die Kosten der Threadverwaltung zu senken. Benutzerdefinierte Threadpools und die Threadpoolimplementierung, die von der Windows-API bereitgestellt werden, sorgen dafür, dass kleine Arbeitsaufgaben effizient parallel ausgeführt werden können. Im Windows-Threadpool befinden sich Arbeitsaufgaben in einer FIFO-Warteschlange (First-in, First-out). Die einzelnen Arbeitsaufgaben werden in der Reihenfolge gestartet, in der sie dem Pool hinzugefügt wurden.

Die Concurrency Runtime implementiert einen Arbeit stehlenden Algorithmus, um den FIFO-Planungsmechanismus zu erweitern. Der Algorithmus verschiebt Aufgaben, die noch nicht gestartet wurden, in Threads, denen die Arbeitsaufgaben ausgehen. Obwohl der Arbeit stehlende Algorithmus Arbeitslasten ausgleichen kann, kann er auch bewirken, dass Arbeitsaufgaben neu angeordnet werden. Durch diese Neuanordnung ist es möglich, dass eine Arbeitsaufgabe in einer anderen Reihenfolge gestartet wird als sie gesendet wurde. Dies ist bei rekursiven Algorithmen sinnvoll, da es in diesem Fall eher möglich ist, dass Daten von neuen Aufgaben gemeinsam genutzt werden als von alten. Wenn die neuen Elemente zuerst ausgeführt werden, bedeutet dies, dass es seltener zu fehlgeschlagenen Zugriffen auf den Cache und möglicherweise zu weniger Seitenfehlern kommt.

Aus der Sicht des Betriebssystems ist das Stehlen von Arbeit unfair. Wenn eine Anwendung jedoch implementiert, dass ein Algorithmus oder eine Aufgabe parallel ausgeführt werden soll, ist Fairness unter den Unteraufgaben nicht immer von Bedeutung. Es geht einzig und allein darum, dass die Aufgabe insgesamt schnell ausgeführt wird. Für andere Algorithmen ist FIFO die geeignete Planungsstrategie.

Verhalten unter verschiedenen Betriebssystemen

Unter Windows XP und Windows Vista verhalten sich Anwendungen, die die Concurrency Runtime verwenden, ähnlich. Als Ausnahme gilt, dass die Heapleistung unter Windows Vista besser ist.

In Windows 7 und Windows Server 2008 R2 unterstützt das Betriebssystem zudem Parallelität und Skalierbarkeit. Diese Betriebssysteme unterstützen beispielsweise Computer, die mehr als 64 Hardwarethreads aufweisen. An einer vorhandenen Anwendung, von der die Windows-API verwendet wird, müssen Änderungen vorgenommen werden, damit diese neuen Funktionen genutzt werden können. Von einer Anwendung, von der die Concurrency Runtime verwendet wird, werden diese Funktionen jedoch automatisch genutzt und es sind keine Änderungen erforderlich.

Sowohl Windows 7 als auch Windows Server 2008 R2 fügen Unterstützung für UMS-Threads (User-mode Schedulable) hinzu. Durch UMS-Threads können Benutzermodusplaner und der Kernel Arbeit effizienter planen. Obwohl UMS nicht auf die vorzeitige Entfernung verzichtet, wird die Effizienz gesteigert, indem Anwendungen und Bibliotheken ohne Kernel-Übergänge kooperativ planen. UMS gibt darüber hinaus Kontrolle an die Anwendung zurück, wenn ein Thread im Kernel blockiert wird, damit die Anwendung während des verbleibenden Zeitanteils weitere Arbeit ausführen kann. Die Concurrency Runtime verwendet UMS-Planung automatisch, wenn sie vom Betriebssystem unterstützt wird. Weitere Informationen zu UMS finden Sie unter Benutzermodusplanung.

[Nach oben]

Vergleich der Concurrency Runtime mit OpenMP

Durch die Concurrency Runtime wird eine Vielzahl von Programmiermodellen ermöglicht. Diese Modelle können sich mit den Modellen anderer Bibliotheken überschneiden oder diese ergänzen. In diesem Abschnitt wird die Concurrency Runtime mit OpenMP verglichen.

Das OpenMP-Programmiermodell ist durch einen offenen Standard definiert und hat klar definierte Verknüpfungen zu den Programmiersprachen Fortran und C/C++. Die Versionen 2.0 und 2.5 von OpenMP sind hervorragend für parallele Algorithmen geeignet, die iterativ sind. Dies bedeutet, dass sie eine parallele Iteration über einem Array von Daten ausführen. OpenMP ist am effizientesten, wenn der Grad der Parallelität vordefiniert ist und den auf dem System verfügbaren Ressourcen entspricht. Das OpenMP-Modell ist besonders für anspruchsvolle Berechnungen geeignet, wenn äußerst umfangreiche Rechenaufgaben auf die Verarbeitungsressourcen eines einzelnen Computers verteilt werden. In diesem Szenario ist die Hardwareumgebung bekannt und der Entwickler kann davon ausgehen, beim Ausführen des Algorithmus exklusiven Zugriff auf Computerressourcen zu haben.

Andere weniger eingeschränkte Computerumgebungen könnten für OpenMP jedoch weniger geeignet sein. Rekursive Probleme (wie der quicksort-Algorithmus oder das Suchen einer Datenstruktur) lassen sich von OpenMP beispielsweise weniger leicht implementieren. Die Concurrency Runtime ergänzt die Funktionen von OpenMP durch die Parallel Patterns Library (PPL) und die Asynchronous Agents Library. Im Gegensatz zu OpenMP stellt die Concurrency Runtime einen dynamischen Planer bereit, der die verfügbaren Ressourcen berücksichtigt und den Grad an Parallelität anpasst, wenn sich die Lastenverteilung ändert.

Viele der in der Concurrency Runtime zur Verfügung stehenden Funktionen können erweitert werden. Darüber hinaus können Sie durch die Kombination bereits vorhandener Funktionen neue Funktionen schaffen. Da OpenMP Compilerdirektiven benötigt, lässt es sich nicht so leicht erweitern.

Weitere Informationen über die Unterschiede zwischen der Concurrency Runtime und OpenMP sowie über das Migrieren von vorhandenem OpenMP-Code zur Concurrency Runtime finden Sie unter Migrieren von OpenMP zur Concurrency Runtime.

[Nach oben]

Siehe auch

Referenz

Übersicht über die Windows-API

Konzepte

Concurrency Runtime

Parallel Patterns Library (PPL)

Asynchronous Agents Library

Weitere Ressourcen

Übersicht über die Concurrency Runtime

OpenMP in Visual C++

Änderungsprotokoll

Datum

Versionsgeschichte

Grund

Juli 2010

Informationen über Migration und Interoperabilität hinzugefügt.

Informationsergänzung.