Was ist Cython? Python mit der Geschwindigkeit von C.

Python hat den Ruf, eine der bequemsten, am besten ausgestatteten und geradezu nützlichsten Programmiersprachen zu sein. Ausführungsgeschwindigkeit? Nicht so viel.

Cython betreten. Die Cython-Sprache ist eine Obermenge von Python, die zu C kompiliert wird und zu Leistungssteigerungen führt, die je nach Aufgabe zwischen einigen Prozent und mehreren Größenordnungen liegen können. Bei Arbeiten, die an die nativen Objekttypen von Python gebunden sind, sind die Beschleunigungen nicht groß. Bei numerischen Operationen oder Operationen, an denen Pythons eigene Interna nicht beteiligt sind, können die Gewinne jedoch enorm sein. 

Mit Cython können Sie viele der nativen Einschränkungen von Python umgehen oder ganz überwinden - ohne auf die Leichtigkeit und Bequemlichkeit von Python verzichten zu müssen. In diesem Artikel werden wir die grundlegenden Konzepte hinter Cython erläutern und eine einfache Python-Anwendung erstellen, die Cython verwendet, um eine ihrer Funktionen zu beschleunigen.

Zugehöriges Video: Verwenden von Cython zur Beschleunigung von Python

Kompilieren Sie Python zu C.

Python-Code kann Aufrufe direkt in C-Module tätigen. Diese C-Module können entweder generische C-Bibliotheken oder Bibliotheken sein, die speziell für die Arbeit mit Python erstellt wurden. Cython generiert die zweite Art von Modul: C-Bibliotheken, die mit Pythons Interna kommunizieren und mit vorhandenem Python-Code gebündelt werden können.

Cython-Code ähnelt von Natur aus Python-Code. Wenn Sie dem Cython-Compiler ein Python-Programm zuführen (Python 2.x und Python 3.x werden beide unterstützt), akzeptiert Cython es so wie es ist, aber keine der nativen Beschleunigungen von Cython kommt ins Spiel. Wenn Sie den Python-Code jedoch mit Typanmerkungen in der speziellen Syntax von Cython dekorieren, kann Cython langsame Python-Objekte durch schnelle C-Äquivalente ersetzen.

Beachten Sie, dass Cythons Ansatz  inkrementell ist . Das bedeutet, dass ein Entwickler mit einer vorhandenen Python-Anwendung beginnen  und diese beschleunigen kann, indem er vor Ort Änderungen am Code vornimmt, anstatt die gesamte Anwendung von Grund auf neu zu schreiben.

Dieser Ansatz passt allgemein zur Art der Software-Leistungsprobleme. In den meisten Programmen konzentriert sich die überwiegende Mehrheit des CPU-intensiven Codes auf einige wenige Hotspots - eine Version des Pareto-Prinzips, auch als „80/20“ -Regel bekannt. Daher muss der größte Teil des Codes in einer Python-Anwendung nicht leistungsoptimiert werden, sondern nur einige wichtige Elemente. Sie können diese Hotspots schrittweise in Cython übersetzen und so die Leistungssteigerungen erzielen, die Sie benötigen, wo es am wichtigsten ist. Der Rest des Programms kann zur Vereinfachung für die Entwickler in Python verbleiben.

Wie benutzt man Cython?

Betrachten Sie den folgenden Code aus der Dokumentation von Cython:

def f (x):

    return x ** 2-x

def integriere_f (a, b, N):

    s = 0

    dx = (ba) / N.

    für i im Bereich (N):

        s + = f (a + i * dx)

    return s * dx

Dies ist ein Spielzeugbeispiel, eine nicht sehr effiziente Implementierung einer integralen Funktion. Als reiner Python-Code ist er langsam, da Python zwischen maschinennativen numerischen Typen und eigenen internen Objekttypen hin und her konvertieren muss.

Betrachten Sie nun die Cython-Version desselben Codes, wobei die Ergänzungen von Cython unterstrichen sind:

 cdef double f (double x):

    return x ** 2-x

def integriere_f (double a, double b, int N):

    cdef int i

    cdef double s, x, dx

    s = 0

    dx = (ba) / N.

    für i im Bereich (N):

        s + = f (a + i * dx)

    return s * dx

Wenn wir explizit die Variablentypen deklarieren, sowohl für die Funktionsparameter und die im Körper der Funktion verwendeten Variablen ( double, intusw.), wird Cython all dies in C. übersetzen wir auch verwenden können cdefKeyword - Funktionen zu definieren, die hauptsächlich in C implementiert, um die Geschwindigkeit zu erhöhen, obwohl diese Funktionen nur von anderen Cython-Funktionen und nicht von Python-Skripten aufgerufen werden können. (Im obigen Beispiel kann nur integrate_fvon einem anderen Python-Skript aufgerufen werden.)

Beachten Sie, wie wenig sich unser tatsächlicher  Code geändert hat. Wir haben lediglich Typdeklarationen zum vorhandenen Code hinzugefügt, um eine signifikante Leistungssteigerung zu erzielen.

Cython Vorteile

Neben der Möglichkeit, den bereits geschriebenen Code zu beschleunigen, bietet Cython mehrere weitere Vorteile:

Die Arbeit mit externen C-Bibliotheken kann schneller sein

Python-Pakete wie NumPy-Wrap-C-Bibliotheken in Python-Schnittstellen erleichtern die Arbeit mit ihnen. Das Hin- und Herwechseln zwischen Python und C über diese Wrapper kann jedoch zu Verzögerungen führen. Mit Cython können Sie direkt mit den zugrunde liegenden Bibliotheken kommunizieren, ohne dass Python im Weg steht. (C ++ - Bibliotheken werden ebenfalls unterstützt.)

Sie können sowohl die C- als auch die Python-Speicherverwaltung verwenden

Wenn Sie Python-Objekte verwenden, werden diese wie in normalem Python speicherverwaltet und müllsammelbar gesammelt. Aber wenn Sie möchten , erstellen und verwalten Sie Ihre eigenen C-Level - Strukturen und die Verwendung malloc/ freezur Arbeit mit ihnen, können Sie dies tun. Denken Sie daran, nach sich selbst aufzuräumen.

Sie können sich je nach Bedarf für Sicherheit oder Geschwindigkeit entscheiden 

Cython führt automatisch Laufzeitprüfungen auf häufig auftretende Probleme durch, die in C auftreten, z. B. den Zugriff außerhalb der Grenzen auf ein Array mithilfe von Dekoratoren und Compiler-Anweisungen (z @boundscheck(False). B. ). Folglich ist von Cython generierter C-Code standardmäßig viel sicherer als handgerollter C-Code, allerdings möglicherweise auf Kosten der Rohleistung.

Wenn Sie sicher sind, dass Sie diese Überprüfungen zur Laufzeit nicht benötigen, können Sie sie für zusätzliche Geschwindigkeitssteigerungen deaktivieren, entweder für ein gesamtes Modul oder nur für ausgewählte Funktionen.

Mit Cython können Sie auch nativ auf Python-Strukturen zugreifen, die das Pufferprotokoll für den direkten Zugriff auf im Speicher gespeicherte Daten verwenden (ohne Zwischenkopie). Mit den Memoryviews von Cython können Sie mit hoher Geschwindigkeit und mit dem für die Aufgabe geeigneten Sicherheitsniveau mit diesen Strukturen arbeiten. Beispielsweise können die einem Python-String zugrunde liegenden Rohdaten auf diese Weise (schnell) gelesen werden, ohne die Python-Laufzeit durchlaufen zu müssen (langsam).

Cython C-Code kann von der Freigabe der GIL profitieren

Pythons Global Interpreter Lock (GIL) synchronisiert Threads innerhalb des Interpreters, schützt den Zugriff auf Python-Objekte und verwaltet Konflikte um Ressourcen. Die GIL wurde jedoch allgemein als Stolperstein für eine leistungsstärkere Python kritisiert, insbesondere auf Multicore-Systemen.

Wenn Sie einen Codeabschnitt haben, der keine Verweise auf Python-Objekte enthält und eine lang laufende Operation ausführt, können Sie ihn mit der with nogil:Direktive markieren  , damit er ohne GIL ausgeführt werden kann. Dies gibt dem Python-Interpreter die Möglichkeit, andere Aufgaben auszuführen, und ermöglicht es Cython-Code, mehrere Kerne zu verwenden (mit zusätzlicher Arbeit).

Cython kann die Python-Typ-Hinweissyntax verwenden 

Python verfügt über eine Syntax mit Typhinweisen, die hauptsächlich von Lintern und Codeprüfern anstelle des CPython-Interpreters verwendet wird. Cython verfügt über eine eigene benutzerdefinierte Syntax für Code-Dekorationen. Mit den jüngsten Überarbeitungen von Cython können Sie jedoch auch die Python-Typ-Hinweis-Syntax verwenden, um Cython grundlegende Typ-Hinweise bereitzustellen. 

Cython kann verwendet werden, um vertraulichen Python-Code zu verschleiern

Python-Module sind trivial einfach zu dekompilieren und zu überprüfen, kompilierte Binärdateien jedoch nicht. Wenn Sie beim Verteilen einer Python-Anwendung an Endbenutzer einige ihrer Module vor gelegentlichem Snooping schützen möchten, können Sie dies tun, indem Sie sie mit Cython kompilieren. Beachten Sie jedoch, dass dies ein Nebeneffekt der Fähigkeiten von Cython ist und nicht eine der beabsichtigten Funktionen.

Cython Einschränkungen

Denken Sie daran, dass Cython kein Zauberstab ist. Es verwandelt nicht automatisch jede Instanz von poky Python-Code in brutzelnden C-Code. Um Cython optimal nutzen zu können, müssen Sie es mit Bedacht einsetzen - und seine Grenzen verstehen:

Geringe Beschleunigung für herkömmlichen Python-Code

Wenn Cython auf Python-Code stößt, der nicht vollständig in C übersetzt werden kann, wird dieser Code in eine Reihe von C-Aufrufen an Pythons Interna umgewandelt. Dies bedeutet, dass der Python-Interpreter aus der Ausführungsschleife entfernt wird, wodurch der Code standardmäßig um 15 bis 20 Prozent beschleunigt wird. Beachten Sie, dass dies ein Best-Case-Szenario ist. In einigen Situationen kann es zu keiner Leistungsverbesserung oder gar Leistungsminderung kommen.

Geringe Beschleunigung für native Python-Datenstrukturen

Python bietet eine Reihe von Datenstrukturen - Zeichenfolgen, Listen, Tupel, Wörterbücher usw. Sie sind äußerst praktisch für Entwickler und verfügen über eine eigene automatische Speicherverwaltung. Aber sie sind langsamer als reines C.

Mit Cython können Sie weiterhin alle Python-Datenstrukturen verwenden, allerdings ohne große Beschleunigung. Dies liegt wiederum daran, dass Cython einfach die C-APIs in der Python-Laufzeit aufruft, die diese Objekte erstellen und bearbeiten. Daher verhalten sich Python-Datenstrukturen im Allgemeinen ähnlich wie Cython-optimierter Python-Code: Manchmal erhalten Sie einen Schub, aber nur wenig. Verwenden Sie für optimale Ergebnisse C-Variablen und -Strukturen. Die gute Nachricht ist, dass Cython es einfach macht, mit ihnen zu arbeiten.

Cython-Code läuft am schnellsten, wenn "reines C"

Wenn Sie eine Funktion in C haben, die mit dem cdefSchlüsselwort beschriftet ist , mit all ihren Variablen und Inline-Funktionsaufrufen für andere Dinge, die reines C sind, wird sie so schnell wie möglich ausgeführt. Wenn diese Funktion jedoch auf einen Python-nativen Code verweist, z. B. eine Python-Datenstruktur oder einen Aufruf einer internen Python-API, ist dieser Aufruf ein Leistungsengpass.

Glücklicherweise bietet Cython eine Möglichkeit, diese Engpässe zu erkennen: Ein Quellcode-Bericht, der auf einen Blick zeigt, welche Teile Ihrer Cython-App reines C sind und welche Teile mit Python interagieren. Je besser die App optimiert ist, desto weniger Interaktion besteht mit Python.

Cython NumPy 

Cython verbessert die Verwendung von C-basierten Bibliotheken von Drittanbietern wie NumPy. Da Cython-Code zu C kompiliert wird, kann er direkt mit diesen Bibliotheken interagieren und Pythons Engpässe aus der Schleife entfernen.

Insbesondere NumPy funktioniert jedoch gut mit Cython. Cython bietet native Unterstützung für bestimmte Konstruktionen in NumPy und bietet schnellen Zugriff auf NumPy-Arrays. Die gleiche bekannte NumPy-Syntax, die Sie in einem herkömmlichen Python-Skript verwenden würden, kann in Cython unverändert verwendet werden.

Wenn Sie jedoch die bestmöglichen Bindungen zwischen Cython und NumPy erstellen möchten, müssen Sie den Code mit der benutzerdefinierten Syntax von Cython weiter dekorieren. Mit dieser  cimportAnweisung kann Cython-Code beispielsweise zur Kompilierungszeit Konstrukte auf C-Ebene in Bibliotheken anzeigen, um die schnellstmöglichen Bindungen zu erzielen.

Da NumPy so weit verbreitet ist, unterstützt Cython NumPy "out of the box". Wenn Sie NumPy installiert haben, können Sie einfach  cimport numpy in Ihrem Code angeben und dann eine weitere Dekoration hinzufügen, um die exponierten Funktionen zu verwenden. 

Cython-Profilerstellung und -Leistung

Sie erzielen die beste Leistung mit jedem Code, indem Sie ihn profilieren und aus erster Hand sehen, wo die Engpässe liegen. Cython bietet Hooks für das cProfile-Modul von Python, sodass Sie Pythons eigene Profiling-Tools wie cProfile verwenden können, um die Leistung Ihres Cython-Codes zu überprüfen. 

In allen Fällen ist es hilfreich, sich daran zu erinnern, dass Cython keine Magie ist - dass immer noch vernünftige reale Leistungspraktiken gelten. Je weniger Sie zwischen Python und Cython hin und her pendeln, desto schneller wird Ihre App ausgeführt.

Wenn Sie beispielsweise eine Sammlung von Objekten haben, die Sie in Cython verarbeiten möchten, iterieren Sie nicht in Python darüber und rufen Sie bei jedem Schritt eine Cython-Funktion auf. Übergeben Sie die gesamte Sammlung an Ihr Cython-Modul und iterieren Sie dort. Diese Technik wird häufig in Bibliotheken verwendet, die Daten verwalten. Daher ist sie ein gutes Modell, um sie in Ihrem eigenen Code zu emulieren.

Wir verwenden Python, weil es Programmierkomfort bietet und eine schnelle Entwicklung ermöglicht. Manchmal geht die Produktivität des Programmierers zu Lasten der Leistung. Mit Cython können Sie mit ein wenig zusätzlicher Anstrengung das Beste aus beiden Welten herausholen.

Lesen Sie mehr über Python

  • Was ist Python? Leistungsstarke, intuitive Programmierung
  • Was ist PyPy? Schnelleres Python ohne Schmerzen
  • Was ist Cython? Python mit der Geschwindigkeit von C.
  • Cython-Tutorial: So beschleunigen Sie Python
  • So installieren Sie Python auf intelligente Weise
  • Die besten neuen Funktionen in Python 3.8
  • Besseres Python-Projektmanagement mit Poetry
  • Virtualenv und venv: Erklärte virtuelle Python-Umgebungen
  • Python virtualenv und venv tun und nicht tun
  • Python-Threading und Unterprozesse erklärt
  • Verwendung des Python-Debuggers
  • Verwendung von timeit zum Profilieren von Python-Code
  • Verwendung von cProfile zum Profilieren von Python-Code
  • Beginnen Sie mit Async in Python
  • So verwenden Sie Asyncio in Python
  • So konvertieren Sie Python in JavaScript (und wieder zurück)
  • Python 2 EOL: Wie man das Ende von Python 2 überlebt
  • 12 Pythons für jeden Programmierbedarf
  • 24 Python-Bibliotheken für jeden Python-Entwickler
  • 7 süße Python-IDEs, die Sie vielleicht verpasst haben
  • 3 Hauptmängel von Python - und ihre Lösungen
  • 13 Python-Webframeworks verglichen
  • 4 Python-Test-Frameworks, um Ihre Fehler zu beseitigen
  • 6 großartige neue Python-Funktionen, die Sie nicht missen möchten
  • 5 Python-Distributionen zur Beherrschung des maschinellen Lernens
  • 8 großartige Python-Bibliotheken für die Verarbeitung natürlicher Sprache