Wie viel Aufwand müssen wir für die Programmierung mehrerer Kerne aufwenden?


12

Prozessoren bekommen heutzutage immer mehr Kerne, was mich wundert ...

Sollten wir Programmierer uns an dieses Verhalten anpassen und mehr Aufwand für die Programmierung mehrerer Kerne betreiben?

Inwieweit sollten wir dies tun und optimieren? Faden? Affinität? Hardware-Optimierungen? Etwas anderes?

Antworten:


15

Egal wie gut Sie sind, es ist unwahrscheinlich, dass Sie ein besseres Schema für die Verwaltung von Threads usw. finden als die Teams , die die Sprache und den Compiler entwickeln, in denen Sie Ihren Code schreiben.

Wenn Sie eine Anwendung mit mehreren Threads benötigen, erstellen Sie die benötigten Threads und lassen Sie den Compiler und das Betriebssystem mit ihren Jobs fortfahren.

Sie müssen wissen, wie diese Threads verwaltet werden, damit Sie die Ressourcen optimal nutzen können. Nicht zu viele Threads zu erstellen, ist ein Beispiel dafür.

Sie müssen auch wissen, was vor sich geht (siehe Lorenzos Kommentar), damit Sie Hinweise zum Thread-Management geben können (oder es in besonderen Fällen außer Kraft setzen können), aber ich hätte gedacht, dass dies nur wenige sind.


3
Ein Thread, der kontinuierlich von einem Kern zu einem anderen springt, hat jedoch Leistungseinbußen (aufgrund des fehlenden CPU-Caches der ersten und zweiten Ebene), insbesondere in Architekturen, in denen zwei unterschiedliche physische Chips verwendet werden. In Multithread-intensivem Code ist Affinität eine gute Sache.
Wizard79

@Lorenzo - In diesem Fall müssen Sie sehen, ob Sie den Thread an einen einzelnen Kern binden können - was vielleicht ein Sonderfall ist -, aber ein interessanter.
ChrisF

1
Wäre es nicht eine merkwürdige Entscheidung für das Betriebssystem, einen aktiven Thread von einem Kern auf einen anderen umzuschalten?
JBRWilkinson

Ich stimme @JBRWilkinson zu, Thread-Affinität scheint mir ein OS-Job zu sein.
Collin

1
@JBRWilkinson Unter Linux (und ich denke, die meisten Betriebssysteme) springen Threads die ganze Zeit zwischen den Kernen. Der erste Grund ist, dass Sie insgesamt viel mehr Threads als Kerne haben. Und wenn einige Fäden absterben, müssen Sie ausbalancieren. Der zweite Grund ist, dass viele Threads schlafen. Und wenn einige aufwachen, denkt der Kernel möglicherweise, dass ein Kern mehr Last als andere hat, und verschiebt einen Thread, häufig Ihren CPU-Hogging-Computing-Thread. Dann laufen 2 CPU-Hogging-Threads auf demselben Kern, bis der Kernel einen zurückbewegt. Wenn Sie einen großen Job in genau num-cores Teile aufteilen, möchten Sie die Thread-Affinität festlegen.
Goswin von Brederlow

5

Ich bin ein .NET-Programmierer und weiß, dass .NET eine allgemeine Abstraktion für Multithreading namens Tasks hat. Es schützt Sie davor, zu viel über das richtige Multithreading gegen das Metall wissen zu müssen. Ich gehe davon aus, dass andere aktuelle Entwicklungsplattformen ähnliche Abstraktionen haben. Wenn Sie also etwas mit Multithreading anfangen wollen, würde ich versuchen, wenn möglich auf dieser Ebene zu arbeiten.

Nun zur Frage, ob Sie sich überhaupt für Multithreading in Ihrer speziellen Anwendung interessieren sollten . Die Antwort auf diese Frage hängt stark von der Bewerbung ab, die Sie schreiben. Wenn Sie eine Anwendung schreiben, die Tausende (oder mehr) unabhängige Dinge verarbeitet, und diese Verarbeitung parallel durchgeführt werden kann, werden Sie mit ziemlicher Sicherheit einen Vorteil aus Multithreading ziehen. Wenn Sie jedoch einen einfachen Dateneingabebildschirm schreiben, bringt Multithreading möglicherweise nicht viel.

Zumindest müssen Sie sich mit Multithreading befassen, wenn Sie an einer Benutzeroberfläche arbeiten. Sie möchten eine Operation mit langer Laufzeit nicht über die Benutzeroberfläche auslösen und sie reagiert nicht mehr, da Sie den Benutzeroberflächenthread für diese Operation entführt haben. Feuern Sie einen Hintergrund-Thread ab und geben Sie dem Benutzer mindestens eine Abbrechen-Schaltfläche, damit er nicht warten muss, bis der Vorgang abgeschlossen ist, wenn er einen Fehler gemacht hat.


5

Im Land von Objective-C, Mac OS X und iOS wurden die Frameworks (wie viele andere) so geschrieben, dass sie die gestiegenen Prozessorkerne ausnutzen und dem Entwickler eine schöne Benutzeroberfläche bieten, um sie zu nutzen.

Ein Beispiel für Mac OS X und iOS ist der Versand von Grand Central. Es gibt libc(meiner Meinung nach) Ergänzungen, um das warteschlangenbasierte Multithreading zu vereinfachen. Anschließend werden (unter anderem) die Frameworks Cocoa und Foundation auf GCD geschrieben, sodass der Entwickler problemlos auf Versandwarteschlangen zugreifen und mit sehr wenig Code auf der Kesselplatte Threading ausführen kann.

Viele Sprachen und Frameworks haben ähnliche Konzepte.


5

Der schwierige Teil besteht darin, Ihren CPU-intensiven Algorithmus auf Ausführungsbausteine ​​aufzuteilen, die als Thread ausgeführt werden könnten.

Dann hat ein Thread, der kontinuierlich von einem Kern zu einem anderen springt, Leistungseinbußen (aufgrund eines fehlenden CPU-Caches der ersten und zweiten Ebene), insbesondere in Architekturen, in denen zwei unterschiedliche physische Chips verwendet werden. In diesem Fall ist Thread-Core-Affinität eine gute Sache.


3

Wir befinden uns jetzt (Oktober 2010) in einer Zeit immensen Wandels.

Wir könnten heute einen 12-Kern-Desktop kaufen.
Wir konnten heute Kauf eine 448 Kernverarbeitungskarte (Suche nach NVidia Tesla).

Es gibt Grenzen, wie viel wir Entwickler in Unkenntnis der enorm parallelen Umgebungen arbeiten können, in denen unsere Programme in naher Zukunft arbeiten werden.

Betriebssysteme, Laufzeitumgebungen und Programmierbibliotheken können nur so viel.

In Zukunft müssen wir unsere Verarbeitung für eine unabhängige Verarbeitung in diskrete Abschnitte unterteilen und dabei Abstraktionen wie das neue .NET "Task Framework" verwenden.

Details wie das Cache-Management und die Affinität bleiben erhalten - sie sind jedoch nur der Beweis für die ultraleistende Anwendung. Kein Entwickler möchte diese Details manuell auf einem 10k-Core-Computer verwalten.


3

Nun, es hängt wirklich davon ab, was Sie entwickeln. Je nachdem, was Sie entwickeln, kann die Antwort von "unbedeutend" bis "absolut kritisch" reichen, und wir erwarten von jedem im Team, dass er die parallelen Implementierungen gut versteht und nutzt.

In den meisten Fällen ist ein solides Verständnis und die Verwendung von Sperren, Threads sowie Tasks und Taskpools ein guter Anfang, wenn Parallelität erforderlich ist. (variiert je nach Sprache / Lib)

Hinzu kommen die Unterschiede in den Designs, die Sie vornehmen müssen - für nicht-triviale Multiprozesse muss man oft mehrere neue Programmiermodelle oder Parallelisierungsstrategien erlernen. In diesem Fall kann ein Team ein Jahr (oder länger) benötigen, um zu lernen, genügend Zeit zu verlieren, um ein solides Verständnis zu erlangen und vorhandene Programme zu aktualisieren. Sobald Sie diesen Punkt erreicht haben, werden Sie (hoffentlich!) Probleme / Implementierungen nicht mehr so ​​wahrnehmen oder angehen wie heute (vorausgesetzt, Sie haben diesen Übergang noch nicht vorgenommen).

Ein weiteres Hindernis besteht darin, dass Sie ein Programm effektiv für eine bestimmte Ausführung optimieren. Wenn Sie nicht viel Zeit haben, um Programme zu optimieren, werden Sie nicht so viel davon profitieren, wie Sie sollten. Eine hohe (oder offensichtliche) Parallelisierung kann die wahrgenommene Geschwindigkeit Ihres Programms mit relativ geringem Aufwand verbessern, und so weit werden heute viele Teams gehen: "Wir haben die wirklich offensichtlichen Teile der App parallelisiert" - das ist in einigen Fällen in Ordnung. Wird der Vorteil, die niedrig hängenden Früchte zu nehmen und eine einfache Parallisierung zu verwenden, in einem angemessenen Verhältnis zur Anzahl der Kerne stehen? oft, wenn es zwei bis vier logische Kerne gibt, aber nicht so oft darüber hinaus. In vielen Fällen ist dies angesichts des Zeitaufwands eine akzeptable Rendite. Dieses parallele Modell ist für viele die Einführung in die Implementierung von Parallelität.

Was Sie mit diesen trivialen parallelen Modellen lernen, ist nicht in allen komplexen parallelen Szenarien ideal. Das effektive Anwenden komplexer paralleler Designs erfordert ein völlig anderes Verständnis und Vorgehen. Diese einfachen Modelle sind häufig voneinander getrennt oder stehen in trivialer Wechselwirkung mit anderen Systemkomponenten. Außerdem lassen sich viele Implementierungen dieser einfachen Modelle nicht gut auf effektiv komplexe parallele Systeme skalieren. Die Ausführung eines schlechten komplexen parallelen Designs kann ebenso lange dauern wie die Ausführung des einfachen Modells. ill: Es wird doppelt so schnell ausgeführt wie das Single-Thread-Modell, wobei während der Ausführung 8 logische Kerne verwendet werden. Die häufigsten Beispiele sind die Verwendung / Erzeugung von zu vielen Threads und ein hohes Maß an Synchronisationsstörungen. Im Allgemeinen wird dies als parallele Verlangsamung bezeichnet. Es ist ziemlich leicht zu begegnen, wenn Sie alle parallelen Probleme als einfache Probleme betrachten.

Nehmen wir also an, Sie sollten in Ihren Programmen wirklich effizientes Multithreading einsetzen (die Minderheit im heutigen Klima): Sie müssen das einfache Modell effektiv einsetzen, um das komplexe Modell zu erlernen, und dann neu lernen, wie Sie den Programmfluss und die Interaktion angehen. Das komplexe Modell ist der Ort, an dem sich Ihr Programm letztendlich befinden sollte, da sich dort heute Hardware befindet und die wichtigsten Verbesserungen vorgenommen werden.

Die Ausführung einfacher Modelle kann wie eine Gabel gedacht werden, und die komplexen Modelle funktionieren wie ein komplexes Ökosystem. Ich denke, das Verständnis für einfache Modelle, einschließlich allgemeiner Sperr- und Threading-Funktionen, sollte oder wird in Kürze von fortgeschrittenen Entwicklern erwartet werden, wenn die Domäne (in der Sie entwickeln) sie verwendet. Das Verständnis komplexer Modelle ist heute (in den meisten Bereichen) noch etwas ungewöhnlich, aber ich denke, die Nachfrage wird recht schnell zunehmen. Als Entwickler sollten viel mehr unserer Programme diese Modelle unterstützen, und die meisten Anwendungen sind weit hinter dem Verständnis und der Implementierung dieser Konzepte zurückgeblieben. Da die Anzahl der logischen Prozessoren einer der wichtigsten Bereiche für die Verbesserung der Hardware ist, wird die Nachfrage nach Personen, die komplexe Systeme verstehen und implementieren können, mit Sicherheit zunehmen.

Schließlich gibt es eine Menge Leute, die denken, die Lösung sei nur "Parallelisierung hinzufügen". Oft ist es besser, die bestehende Implementierung zu beschleunigen. es ist in vielen Fällen viel einfacher und unkomplizierter. Viele Programme in freier Wildbahn wurden nie optimiert. Einige hatten nur den Eindruck, dass die nicht optimierte Version eines Tages bald von der Hardware verdrängt werden würde. Die Verbesserung des Designs oder der Anzahl vorhandener Programme ist auch eine wichtige Fähigkeit, wenn die Leistung wichtig ist - mehr Kerne auf Probleme zu werfen, ist nicht unbedingt die beste oder einfachste Lösung.

Bei der Ausrichtung auf moderne PCs müssen die meisten von uns, die gute parallele Systeme implementieren müssen, nicht über Multithreading, Sperren, parallele Bibliotheken, das Lesen eines Buches und viel Erfahrung beim Schreiben und Testen von Programmen hinausgehen (im Grunde bedeutet dies eine erhebliche Umstrukturierung Ihrer Arbeitsweise) Annäherung an das Schreiben von Programmen).


2

Das tun wir, aber wir schreiben eine rechenintensive Software, sodass wir direkt von mehreren Kernen profitieren.

Manchmal verschiebt der Scheduler Threads häufig zwischen Kernen. Wenn dies nicht akzeptabel ist, können Sie mit der Kernaffinität spielen.


0

Derzeit wird die Prozessorfrequenz in naher Zukunft nicht steigen. Wir bleiben bei der 3-GHz-Marke (ohne Übertaktung). Sicherlich ist es für viele Anwendungen möglicherweise nicht erforderlich, über das grundlegende Multithreading hinauszugehen. Wenn Sie eine Benutzeroberflächenanwendung erstellen, sollte jede intensive Verarbeitung auf einem Hintergrundthread erfolgen.

Wenn Sie eine Anwendung erstellen, die große Datenmengen in Echtzeit verarbeitet, sollten Sie sich wahrscheinlich mit Multithreading-Programmierung befassen.

Bei der Multithread-Programmierung werden Sie feststellen, dass sich Ihre Leistung verschlechtert. Sie können Stunden damit verbringen, das Programm um 15% zu verbessern, und dann eine weitere Woche damit verbringen, es nur um weitere 5% zu verbessern.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.