Moderne Computer sind meist mit mehreren Prozessorkernen ausgestattet, und wenn alles reibungslos funktioniert, sollte jeder Kern ständig mit der Verarbeitung beschäftigt sein. Jeder Kern erhält eine Warteschlange mit Aufgaben – Threads, Tasks usw.– und der Scheduler verteilt diese Aufgaben. Schwierig wird es, wenn Threads während der Ausführung neue Threads erzeugen oder zusätzliche Aufgaben verursachen. Diese werden nicht unbedingt von demselben Kern bearbeitet, der bereits an etwas arbeitet, insbesondere wenn es sich um einen untergeordneten Thread handelt. Sie können je nach Planungsstrategie des Betriebssystems demselben oder einem anderen Kern zugewiesen werden.

Meistens sind alle Kerne mit Arbeit versorgt. Doch was passiert, wenn einer früher fertig ist? Hier kommt Work Stealing ins Spiel: Wenn ein Kern seine Aufgaben erledigt hat, stöbert er herum und „stiehlt“ einen Job aus der Warteschlange eines anderen Kerns. So bleibt kein Kern untätig und verschwendet Potenzial. In der Praxis kann dies die Gesamtleistung deutlich verbessern, insbesondere bei Workloads, die nicht von Anfang an perfekt ausbalanciert sind. Sie werden möglicherweise Leistungssteigerungen feststellen, wenn Ihr System oder Ihre App diesen parallelen Ninja-Move unterstützt.

Vorteile und Nachteile

Work Stealing hält den Prozessor durch dynamische Umverteilung der Arbeit am Laufen. Dies verhindert Leerlaufzeiten des Kerns, sodass der Gesamtdurchsatz deutlich gesteigert werden kann – insbesondere bei Workloads, bei denen die Aufgaben zu Beginn nicht gleichmäßig aufgeteilt werden. Aber es ist nicht alles rosig. Es entsteht ein gewisser Overhead, vor allem, weil ein Kern, der Arbeit stiehlt, möglicherweise Daten zurück in seinen Cache laden muss (oder sie bei Cache-Fehlern aus dem System-RAM abrufen muss).Dieser Cache-Fehler kann die Leistung verlangsamen, da er auf das Laden der Daten wartet, was den Zweck zunichte macht, wenn die gestohlene Aufgabe schneller auf dem ursprünglichen Kern hätte gestartet werden können.

Ehrlich gesagt funktioniert dieser Prozess auf manchen Systemen hervorragend, auf anderen kann er jedoch zu kleinen Verzögerungen führen. Es ist schon seltsam, aber auf manchen Maschinen kann Work Stealing mehr Cache-Thrashing als Nutzen verursachen. Je mehr Kerne, desto komplexer wird der Balanceakt.

Implementierungen

Dies ist nicht nur eine CPU-Sache. Viele Programmierumgebungen bieten integrierte Unterstützung für Work Stealing – denken Sie an Sprachen wie Cilk (verwendet im Hochleistungsrechnen), Rusts Tokio-Runtime oder die Task Parallel Library von. NET. Sie verwalten die Arbeitsverteilung im Hintergrund und vermitteln so die Illusion müheloser Parallelität. Das Betriebssystem selbst übernimmt zudem einen Großteil der Schwerstarbeit, indem es Aufgaben plant und Thread-Pools verwaltet, in der Regel über APIs wie pthread unter Linux oder Windows ThreadPool unter Windows.

In Multiprozesssystemen werden Aufgaben häufig einem Pool von Arbeitsthreads hinzugefügt, die das Betriebssystem auf die verfügbaren Kerne verteilt, anstatt bestimmte Kerne bestimmten Aufgaben zuzuweisen. Hier kommt es zum Work-Stealing: Arbeitsthreads können sich gegenseitig Aufgaben aus der Warteschlange „stehlen“, um alle Kerne zu beschäftigen. Die Auswahl der Aufgaben kann unterschiedlich sein: Manche Systeme wählen einen zufälligen Kern aus und stehlen die letzte Aufgabe in seiner Warteschlange, andere den Kern mit der höchsten Auslastung usw.

Letztendlich ist Work Stealing nur eine der cleveren Techniken, die in vielen Multicore-Systemen zum Einsatz kommen, um die Arbeitslast gleichmäßig zu verteilen und CPU-Leerläufe zu vermeiden. Es ist ein grundlegender Bestandteil moderner Parallelverarbeitung, auch wenn die meisten Benutzer es nicht direkt wahrnehmen.

Abschluss

Im Hintergrund arbeitet Work Stealing und hält alle Kerne beschäftigt, indem Aufgaben dynamisch von überlasteten auf inaktive Kerne umverteilt werden. So maximieren Multicore-CPUs die Effizienz, ohne dass der Benutzer die Arbeitslast manuell verteilen muss. Natürlich ist das System nicht perfekt – es entsteht Overhead, und in manchen Fällen kann es zu Cache-Fehlern kommen, die das System etwas verlangsamen. Aber insgesamt kann es, wenn Ihr System es richtig nutzt, dazu führen, dass Multithread-Programme deutlich reibungsloser laufen.