Programmierung und Softwareentwicklung

Wie man Numba zur Beschleunigung rechenintensiver Python-Modelle im Finanzdienstleistungssektor einsetzt

Chad Schuster von Milliman erläutert, wie Numba Teile von Python-Programmen über LLVM in optimierten Code umwandeln kann und dabei parallele Verarbeitung sowie GPU-Einheiten nutzt. Das Experiment zeigt erhebliche Leistungsgewinne, offenbart jedoch auch Einschränkungen bei objektorientierter Programmierung, Typinferenz und Kompilierungszeit. Dadurch wird die Auswahl geeigneter Teile zur Beschleunigung zu einem entscheidenden Faktor.

2026-08-27
5 Min. Lesezeit
13 Aufrufe
فريق تحرير certi.news
Wie man Numba zur Beschleunigung rechenintensiver Python-Modelle im Finanzdienstleistungssektor einsetzt

Chad Schuster, Principal im Bereich Financial Risk Management bei Milliman, stellte einen praktischen Ansatz zum Aufbau leistungsstarker Rechenmodelle mit Python und Numba vor, anstatt vollständig auf Anwendungen in C++ zu setzen. Ausgangspunkt ist ein verbreitetes Problem im Finanzdienstleistungssektor: Modelle, die Cashflows über eine große Zahl von Szenarien simulieren, benötigen erhebliche Rechenleistung, während Teams die schnelle Entwicklung und die einfache Wartbarkeit von Python beibehalten möchten.

Das Problem ist besonders bei Lebensversicherungsmodellen und Altersvorsorgeprodukten wie Annuitäten relevant, bei denen Berechnungen zur Bewertung künftiger Verpflichtungen und zur Ausführung mehrerer Szenarien verwendet werden. Der Präsentation zufolge setzten Versicherungsunternehmen historisch auf lokale Netzwerke mit 5.000 bis 10.000 Knoten. Der Wechsel in die Cloud machte jedoch die Laufzeit und die Kosten jedes Vorgangs für Infrastrukturentscheidungen transparenter.

Was fügt Numba zu Python hinzu?

Das traditionelle Python beziehungsweise CPython interpretiert Code während der Ausführung, während kompilierte Sprachen wie C++ den Code vor der Ausführung in Maschinencode umwandeln. Numba versucht, diese Lücke durch Just-in-Time-Kompilierung zu verkleinern: Geeignete Funktionen werden während der Programmausführung mit LLVM kompiliert, anschließend wird die ursprüngliche Funktion durch die kompilierte Ausführung ersetzt.

Entwickler aktivieren diesen Prozess üblicherweise über Python-Dekoratoren wie JIT oder njit. Numba arbeitet auf Funktionsebene, untersucht den Code und wandelt ihn in eine eigene Zwischenrepräsentation um. Danach leitet es die Typen der Variablen und Parameter sowie die Rückgabewerte ab, bevor es die Repräsentation in LLVM IR überführt und die erforderlichen Optimierungen vornimmt. Wird eine Funktion mit unterschiedlichen Typen aufgerufen, kann Numba für jede Typkombination spezialisierte kompilierte Implementierungen erzeugen – durch das, was Numba polymorphic dispatch nennt.

Leistungsgewinne sind keine feste Größe

Im von Schuster vorgestellten Proof of Concept machte Numba das Programm im Vergleich zu interpretiertem Python etwa 75-mal schneller. In einem anderen Modell fiel das Ergebnis anders aus: Die Verlagerung der rechenintensiven numerischen Berechnungen auf Numba auf der CPU führte zu einer Beschleunigung um etwa das Zweifache. Der anschließende Wechsel auf eine GPU brachte in diesem konkreten Lauf eine zusätzliche Beschleunigung um den Faktor 750. Die Präsentation erwähnte, dass dieses Verbesserungsniveau die GPU-Einheit in diesem Lauf ungefähr 750 verwendeten Kernen gleichstellte und die geschätzten Kosten auf etwa ein Zehntel senkte.

Diese Ergebnisse sind jedoch kein allgemeines Versprechen für jede Anwendung. Der Gewinn hängt vom Anteil des kompilierbaren Codes, vom Verhältnis der Rechenoperationen zu den Ein-/Ausgabeoperationen, von der Effizienz des ursprünglichen Python-Codes und von LLVMs Fähigkeit ab, den erzeugten Code zu optimieren. Außerdem eignet sich die Verarbeitung auf einer GPU nicht für jeden Algorithmus. Daher sollte der tatsächliche Engpass gemessen werden, bevor das Modell neu entworfen wird.

Was ändert sich praktisch für Engineering-Teams?

Der Ansatz empfiehlt, die Schichten für Datenaufbereitung sowie Ein- und Ausgabe in Python zu belassen und nach Möglichkeit nur den rechenintensiven numerischen Teil nach Numba zu verlagern. Dadurch wird der Umfang der Neuentwicklung begrenzt und ein großer Teil der Python-Umgebung beibehalten, während sich die Optimierungsarbeit auf die Funktionen konzentriert, die den größten Anteil der Laufzeit beanspruchen. Wenn die numerischen Funktionen begrenzt und klar abgegrenzt sind, kann ein Versuch mit Numba laut Schuster eine direkte Option für diejenigen sein, die innerhalb von Python bleiben möchten.

Wird hingegen umfangreiche und komplexe Logik in Numba integriert, steigen die Kosten für Entwicklung und Wartung. Das Experiment nutzte NumPy-Arrays, Tupel und einfache Datenstrukturen, da Numba nicht alle Eigenschaften von Python unterstützt. Zu den genannten Einschränkungen gehören Dictionaries mit flexiblen Typen, Ausnahmen, Context Manager, Closures und über Comprehensions erstellte Listen sowie die eingeschränkte Unterstützung einiger verbreiteter Funktionen wie print, sorted und getattr.

Einschränkungen, die vor dem Einsatz berücksichtigt werden müssen

Die objektorientierte Programmierung bleibt in diesem Experiment ein wichtiger Schwachpunkt. Numba bietet experimentelle Funktionen wie jitclasses und structrefs, um ein objektähnliches Verhalten zu ermöglichen. Diese können sich jedoch zwischen Versionen ändern und unterstützen keine GPU, wodurch sie für den vom Team gewählten Ansatz ungeeignet waren. Deshalb setzte die Anwendung auf einen eher funktionalen Stil und einfache Datenstrukturen, obwohl ein objektorientiertes Design aus Gründen der Wartbarkeit und der Übergabe der Modelle an Kunden wünschenswert war.

Auch Fehler bei der Typinferenz und beim Lowering können schwer nachzuverfolgen sein, insbesondere in Programmen mit vielen Aufrufebenen. Die Fehlermeldung kann auf eine Funktion verweisen, die weit von der Stelle entfernt ist, an der das Problem tatsächlich entstanden ist. Ein vorgeschlagener praktischer Ansatz besteht darin, bei Bedarf JIT statt njit zu verwenden, sodass Numba vorübergehend deaktiviert und zur leichteren Fehlersuche auf interpretiertes Python zurückgegriffen werden kann. Für den produktiven Betrieb lässt sich die Beschleunigung anschließend wieder aktivieren.

Außerdem entsteht beim ersten Aufruf jeder Funktion eine anfängliche Kompilierungszeit, die sich vergrößern kann, wenn Inlining umfassend eingesetzt wird. Um diese Verzögerung zu vermeiden, kann Ahead-of-Time-Kompilierung verwendet werden. Dadurch kann jedoch die Fähigkeit des Codes eingeschränkt werden, sich im Vergleich zur Just-in-Time-Kompilierung an die tatsächliche Hardware anzupassen.

Redaktionelle Einordnung: Der zentrale Wert dieses Experiments liegt nicht in der Zahl 750 an sich, sondern in der Methode, die Leistungsmessung mit der Aufteilung des Modells verbindet. Numba eignet sich, wenn der Engpass rechenbedingt ist und in Funktionen mit klaren Typen und Strukturen isoliert werden kann. Wird dagegen ein komplettes Python-System in kompilierbaren Code umgewandelt, kann sich das Problem von langsamer Ausführung zu höherer Komplexität bei Entwicklung und Fehlersuche verlagern. Daher sollten Finanz- und Engineering-Teams Geschwindigkeit, Wartbarkeit, Kompilierungszeit und GPU-Kompatibilität abwägen, bevor sie Numba als umfassenden Ersatz für C++ oder für eine weitergehende Neugestaltung des Systems betrachten.

Nachrichtenquelle
InfoQ - Architecture Articles
Originalquelle öffnen ↗
ف
Autor

فريق تحرير certi.news

Aus derselben Kategorie

Das könnte Sie interessieren

Alle Nachrichten anzeigen