Im März 2005 veröffentlichte Herb Sutter seinen berühmten Artikel „The Free Lunch Is Over“ und sagte eine Revolution der nebenläufigen Programmierung voraus, die ebenso bedeutend sein würde wie die objektorientierte Revolution. Hier ein kurzer Auszug aus dem Artikel, der die Motivation hinter dieser Prognose erläutert:
Die großen Prozessorhersteller und -architekturen – von Intel und AMD bis Sparc und PowerPC – stoßen mit den meisten traditionellen Ansätzen zur Steigerung der CPU-Leistung an ihre Grenzen. Statt Taktraten und den Durchsatz linearer Befehlsfolgen immer weiter zu erhöhen, setzen sie nun auf breiter Front auf Hyperthreading- und Multicore-Architekturen. Beide Technologien sind bereits heute auf Chips verfügbar; insbesondere Multicore ist auf aktuellen PowerPC- und Sparc-IV-Prozessoren vorhanden und wird 2005 auch von Intel und AMD kommen. Tatsächlich waren Multicore-Prozessoren das große Thema des In-Stat/MDR Fall Processor Forum 2004, auf dem viele Unternehmen neue oder aktualisierte Multicore-Prozessoren präsentierten. Rückblickend ist es daher kaum übertrieben, 2004 als das Jahr von Multicore zu bezeichnen.
Heute wissen wir, dass das Mooresche Gesetz nicht unbegrenzt weitergelten kann, wie hier erläutert wird
Die meisten Prognostiker der Halbleiterindustrie, darunter Gordon Moore, erwarten, dass das Mooresche Gesetz etwa um 2025 an sein Ende gelangt. Im April 2005 erklärte Gordon Moore in einem Interview, dass sich diese Entwicklung nicht unbegrenzt fortsetzen lasse: „Es kann nicht ewig so weitergehen. Exponentielle Entwicklungen haben die Eigenschaft, dass man sie immer weiter fortschreibt, bis irgendwann eine Katastrophe eintritt.“ Er wies außerdem darauf hin, dass Transistoren letztlich an die Grenzen der Miniaturisierung auf atomarer Ebene stoßen würden
Gleichzeitig statten Prozessorhersteller jede neue Prozessorgeneration weiterhin mit mehr Kernen aus. So verfügt beispielsweise die Intel-E7-Xeon-Familie über 24 Kerne.
Zurück zu Herb Sutters Prognose. Er schreibt:
Nebenläufigkeit ist die nächste große Revolution in der Art und Weise, wie wir Software entwickeln.
Und
Anwendungen werden zunehmend nebenläufig sein müssen, wenn sie die weiterhin exponentiell steigende CPU-Gesamtleistung vollständig ausschöpfen wollen. Effizienz und Leistungsoptimierung werden dadurch wichtiger, nicht weniger wichtig.
Dreizehn Jahre nach dieser Prognose stellt sich die Frage: Hat Nebenläufigkeit die Art und Weise, wie wir Software schreiben, tatsächlich revolutioniert? Oder müssen wir noch einige Jahre warten, bis sich diese Revolution vollständig entfaltet?
Wir wissen, dass die Arbeit mit Multithreading- und Multicore-Systemen nicht einfach ist und viele Entwickler dabei auf erhebliche Schwierigkeiten stoßen. Ein kurzer Blick in Entwicklerforen zeigt Aussagen wie diese:
Ich halte mich für einen recht guten Programmierer, und auch mein Chef ist ein recht guter Programmierer. Trotzdem scheint er einige Aufgaben wie Multithreading und deren Schwierigkeit zu unterschätzen (ich empfinde alles, was über das Starten einiger Threads, das Warten auf deren Abschluss und die anschließende Rückgabe der Ergebnisse hinausgeht, als ziemlich schwierig).
Sobald man sich mit Deadlocks und Race Conditions befassen muss, wird es meiner Meinung nach sehr anspruchsvoll. Mein Chef scheint das jedoch nicht wirklich zu erkennen – ich glaube nicht, dass er jemals selbst damit konfrontiert war. Seine Haltung lautet im Grunde: einfach einen Lock setzen.
Wie kann ich ihm also vermitteln oder erklären, dass er die Komplexität von Nebenläufigkeit, Parallelität und Multithreading möglicherweise unterschätzt? Oder liege vielleicht ich falsch?Genau darauf wies Herb Sutter in seinem Artikel hin:
Die große Mehrheit der Programmierer versteht Nebenläufigkeit heute noch nicht wirklich – genauso wie die große Mehrheit der Programmierer vor 15 Jahren Objekte noch nicht wirklich verstanden hatte. Das Programmiermodell für Nebenläufigkeit lässt sich jedoch erlernen, insbesondere wenn wir bei nachrichten- und lockbasierter Programmierung bleiben. Hat man es einmal verstanden, ist es nicht wesentlich schwieriger als objektorientierte Programmierung und kann hoffentlich ebenso selbstverständlich werden. Man muss lediglich bereit sein, in Schulung und Zeit zu investieren – für sich selbst und für das eigene Team.
Sind sich Entwickler heute der Vorteile von Nebenläufigkeit bewusst? Werden Projekte so entworfen, dass sie diese Möglichkeiten optimal nutzen, oder benötigen wir weiterhin Spezialisten, um effizienten nebenläufigen Code zu entwickeln? Ist die Revolution angekommen?
Ja, die Revolution ist da – sie wurde jedoch nicht allein von Entwicklern vorangetrieben. Sie begann bereits vor Jahren mit neuen Programmiersprachen sowie mit neuen Bibliotheken und Standards für etablierte Sprachen. Entwickler brauchen Sprachen, mit denen sich die Möglichkeiten der Nebenläufigkeit leichter vollständig ausschöpfen lassen. Sich ausschließlich auf Low-Level-APIs zu verlassen, ist in der Regel keine gute Idee, da dadurch zahlreiche Fehler und andere Probleme entstehen können.
Rust, Go und Clojure sind Beispiele für moderne Sprachen, bei deren Entwurf Nebenläufigkeit ausdrücklich berücksichtigt wurde.
So lautet das Motto von Rust:
Rust ist eine Systemprogrammiersprache, die extrem schnell läuft, Segmentation Faults verhindert und Thread-Sicherheit garantiert.
Und so wird Clojure beschrieben:
Clojure ist eine dynamische Allzweck-Programmiersprache, die die Zugänglichkeit und interaktive Entwicklung einer Skriptsprache mit einer effizienten und robusten Infrastruktur für Multithread-Programmierung.
Diese neueren Sprachen werden immer beliebter, doch es bleibt schwierig, mit etablierten Sprachen wie C, C++, Java und C# zu konkurrieren. Allerdings haben diese etablierten Sprachen im Laufe der Jahre Funktionen und Bibliotheken erhalten, die Entwicklern helfen, die Vorteile der Nebenläufigkeit zu nutzen und effizienten nebenläufigen Code zu schreiben. Genau darauf wies Herb Sutter in seinem Artikel hin:
Schließlich werden Programmiersprachen und Systeme zunehmend gezwungen sein, Nebenläufigkeit gut zu unterstützen.
So führte beispielsweise Microsoft® .NET Framework 4 ein paralleles Programmiermodell ein, das alle verfügbaren CPU-Kerne nutzen und Anwendungscode parallel ausführen kann, wodurch sich die Leistung von C#-Programmen verbessert. Mit jeder neuen Version des .NET Framework kamen weitere Funktionen hinzu, die die Multicore-Programmierung vereinfachten.
Für C++ wies Herb Sutter damals darauf hin, dass es überhaupt keine standardisierte Unterstützung für Nebenläufigkeit gab:
Die Sprache C++ wird seit Langem erfolgreich zur Entwicklung anspruchsvoller Multithread-Systeme eingesetzt, besitzt jedoch überhaupt keine standardisierte Unterstützung für Nebenläufigkeit (der ISO-C++-Standard erwähnt Threads nicht einmal – und das bewusst). Daher muss Nebenläufigkeit in der Regel zwangsläufig über nicht portable, plattformspezifische Funktionen und Bibliotheken realisiert werden. (Oft ist die Unterstützung zudem unvollständig: Statische Variablen dürfen beispielsweise nur einmal initialisiert werden, wofür der Compiler sie normalerweise mit einem Lock schützen müsste; viele C++-Implementierungen erzeugen diesen Lock jedoch nicht.)
Glücklicherweise hat die 2011 begonnene C++-Renaissance Entwicklern viele nützliche Funktionen gebracht, die die Multithread- und Multicore-Programmierung erleichtern.
Zusammenfassend lässt sich sagen: Die Revolution ist bereits da – sowohl im Design neuer Programmiersprachen als auch durch neue Funktionen in etablierten Sprachen. Nun liegt es an den Entwicklern, diese Möglichkeiten zu entdecken und effektiv zu nutzen. Keine Sorge: Nebenläufige Programmierung ist längst nicht mehr so abschreckend wie früher.
Letztlich hatte Herb Sutter recht – angesichts seiner langjährigen Expertise ist das kaum überraschend. Seit 2011 hat er zudem maßgeblich zur Entwicklung nützlicher Funktionen für Nebenläufigkeit beigetragen, beginnend mit dem C++11-Standard.
