Programmiersprache: Julia 1.5 stabilisiert die Multithreading-API

Das aktuelle Release der funktionsorientierten Programmiersprache konzentriert sich auf Multithreading und die Speicherverwaltung für Structs.

In Pocket speichern vorlesen Druckansicht 8 Kommentare lesen
Programmiersprache: Julia 1.5 stabilisiert die Multithreading-API
Lesezeit: 5 Min.
Von
  • Rainald Menge-Sonnentag
Inhaltsverzeichnis

Die Programmiersprache Julia ist in Version 1.5 erschienen. Das aktuelle Release stabilisiert die APIs für Multithreading, die damit nicht mehr als experimentell gelten. Außerdem hat das Julia-Team das Allozieren von Speicher für struct-Objekte optimiert. Darüber hinaus existiert eine neue Kurzform für Tupels und Parameter, und die Compiler-Optimierung lässt sich für einzelne Module festlegen.

Wie die vorangegangenen Minor Releases bietet Julia 1.5 keinen Long-term Support (LTS). Damit bleibt das 2018 veröffentlichte Julia 1.0 das einzige LTS-Release. Allerdings bringt das aktuelle Release wie die anderen Versionen seit Julia 1.1 keine Inkompatibilitäten in Form von Breaking Changes mit.

Natives Multithreading kennt Julia seit Version 0.5, die 2016 erschienen ist. Das 1.3-Release brachte Ende 2019 einige Ergänzungen für das nebenläufige Programmieren, darunter das @spawn-Makro, aber bisher war die API als experimentell gekennzeichnet. Das ändert sich in Julia 1.5: Der Großteil der Multithreading-API gilt nun als stabil.

Dafür hat das Team einige Anpassungen vorgenommen, um in wichtigen Bereichen Thread-Sicherheit zu gewährleisten, unter anderem für globale Zuweisungen, Typdefinitionen und Module. Darüber hinaus gelten nun @sync und die SuiteSparse-Bindings als Thread-safe. Zudem bringt das Release Performance-Optimierungen beim Wechseln des aktiven Task mit, und Entwickler können mit dem Kommandozeilenparameter -t die Zahl der Threads festlegen.

Julia kennt von Haus aus sowohl Immutables (unveränderliche Objekte) als auch veränderliche Objekte in Form von Mutables. struct-Objekte sind standardmäßig unveränderlich, aber das Erstellen veränderlicher Structs ist über die explizite Definition als mutable struct ebenfalls möglich.

Hinsichtlich des Speicherlayouts und der Aufrufe orientiert sich Julia an C und C++. Üblicherweise legt es veränderliche Objekte an einer festen Position auf dem Heap ab und übergibt sie stets als Referenz. Für Immutables kann der Compiler flexibler arbeiten und damit bessere Optimierungen vornehmen. Für ein struct, das zwei Werte enthält, kann die Übergabe durch Ablage der beiden Inhalte in Registern erfolgen. Der ursprünglich Speicherort ist unabhängig vom Programmfluss irrelevant, da sich der Inhalt per Definition des Immutable nicht ändert.

Bisher gab es dabei eine Hürde: Wenn ein Immutable-Objekt auf ein veränderliches Objekt verweist, das auf dem Heap liegt, musst der Compiler das an sich unveränderliche Objekt ebenfalls auf dem Heap speichern, damit der Garbage Collector sich beim Aufräumen nicht verstolpert. Dank eines Redesigns ist dieser Umweg nun nicht mehr erforderlich.

Damit kann der Compiler nun alle Immutables auf dem Stack allozieren, auch wenn ihre Felder veränderliche Objekte referenzieren. Die Optimierung betrifft einige Abstraktionen in Julia, darunter den SubArray-Typ beziehungsweise Array-View-Typen, um Teile eines Arrays an eine Funktion zu übergeben, ohne den Inhalt zu kopieren.

Eine weitere Neuerung widmet sich der Compiler-Optimierung und der damit verbundenen Balance zwischen möglichst geringer Compile-Zeit auf der einen und hoher Performance des kompilierten Codes auf der anderen Seite. Standardmäßig nutzt Julia den Parameter -O2, der wohl in etwa dasselbe Maß an Optimierung erzeugt wie der entsprechende Parameter für clang beziehungsweise gcc.

Auch wenn die hohe Optimierung die bestmögliche Performance für das Programm gewährleistet, geht sie zu Lasten der Compile-Zeit, und nicht jedes Codefragment benötigt entsprechende Maßnahmen. Daher lässt sich das Optimierungs-Level nun modulweise angeben. Das Plotting-Modul Plot.jl setzt beispielsweise über @optlevel 1fest, dass es die -O1-Optimierung wünscht.

Eine kleine Ergänzung betrifft Parameter und Tupel-Elemente, bei denen der Name und der Inhalt gleich sind. Für sie gilt künftig folgende Abkürzung:

# Die Zeile
printstyled("text"; color) 
# ist eine Abk�rzung f�r 
printstyled("text"; color = color)

Entwicklerinnen und Entwickler müssen dabei vor dem ersten abgekürzten Parameter das Semikolon setzen, auch wenn es sich um den ersten Parameter beziehungsweise das erste Tupel-Element handelt wie in folgendem Beispiel, das wie obiges aus dem Julia-Blog stammt:

# Der Tupel
(; name, value, type) 
# ist eine Kurzform von
(name = name, value = value, type = type).

Die Kurzform funktioniert auch für Felder in Structs oder andere über die object.field-Syntax geschriebene Elemente:

# Der Aufruf
printstyled("text"; opts.color)
# entspricht der Form
printstyled("text"; color = opts.color).

Zu den weiteren nennenswerten Ergänzungen gehört das in Julia 1.5 eingeführte @ccall-Makro als übersichtlichere Schreibweise zum Aufruf von C-Funktionen:

# Der Aufruf �ber das Makro
@ccall strlen("hello"::Cstring)::Csize_t
# entspricht der herk�mmlichen Syntax f�r C-Aufrufe 
ccall(:strlen, Csize_t, (Cstring,), "hello")

Außerdem arbeitet die Random-Library zum Erstellen von Zufallszahlen wohl deutlich effizienter sowohl für Fließkommazahlen als auch für boolesche Werte.

Weitere Neuerungen wie die angepassten Scopes für die Read Evaluate Print Loop (REPL) lassen sich dem Julia-Blog entnehmen. Letzte Woche fand die kostenlose Online-Ausgabe der JuliaCon statt, und die Vorträge lassen sich im Nachgang abrufen. Passend zur Onlinekonferenz ist das Julia-Plug-in für Visual Studio Code als 1.0-Release erschienen.

Julia ist eine dynamische Programmiersprache, die zwar als General Purpose Language funktioniert, aber vor allem auf numerische und wissenschaftliche Anwendungen ausgelegt ist. Die Designer der Sprache sind Jeff Bezanson, Alan Edelman, Stefan Karpinski und Viral B. Shahwaren. Julia zieht keine klaren Grenzen, sondern will die Vorzüge dynamischer und statischer Sprachen vereinen. Mit acht Jahren ist die Programmiersprache vergleichsweise jung.

(rme)