AI-United » Allgemein » Verwenden von Cython zur Beschleunigung des Python-Codes um mehr als das 30-Fache

Verwenden von Cython zur Beschleunigung des Python-Codes um mehr als das 30-Fache

Python ist die derzeit beliebteste Programmiersprache der Welt, gefolgt von C++ und C! Ihr größter Vorteil besteht darin, dass sie bei weitem am einfachsten zu bedienen ist, da der Code auf eine intuitiv und menschenlesbare Weise geschrieben ist. 

Sie hat jedoch einen Nachteil, über den immer wieder gesprochen wird, überwiegend von den C-Code-Gurus: Python ist langsam.

Und dies stimmt.

Verglichen mit anderen allgemein verwendeten Programmiersprachen ist Python wirklich langsam. Dies wurde von Benchmark game bewiesen, das einige solide Benchmarks zur Verfügung stellt, mit denen die Geschwindigkeit einer Reihe von Programmiersprachen für verschiedene Aufgaben verglichen wird.

Zwei der wichtigsten Möglichkeiten, den ganzen Prozess zu beschleunigen, sind:

  1. Einsatz der Multi-Processing-Bibliotheken, die das Verwenden aller CPU-Kerne ermöglichen
  2. Einsatz von Rapids zur Beschleunigung der Verarbeitung auf der GPU bei der Arbeit mit Numpy, Pandas oder Scikit-Learn.

Diese Möglichkeiten sind dann sehr hilfreich, wenn es sich um Parallelisierung der Prozesse handelt wie beispielsweise Datenvorverarbeitung oder Matrixoperationen.

Es gibt jedoch eine Reihe von Fällen, bei denen eine Möglichkeit bestehen sollte, Python selbst zu beschleunigen: Der Code ist reines Python; Es gibt eine große for-Schleife, die nur verwendet werden muss und nicht in eine Matrix eingefügt werden kann, weil es notwendig ist, Daten nacheinander zu verarbeiten. 

In diesen Fällen wird Cython eingesetzt. Neben der Anbindung von externen Bibliotheken an den CPython-Interpreter ist das zweite Haupteinsatzgebiet von Cython die Beschleunigung von rohem Phyton-Code.

Cython: Definition

Im Grunde genommen handelt es sich bei Cython um einen Zwischenschritt zwischen Python und C/C ++. Mit ihrer Hilfe kann der reine Python-Code mit einigen kleinen Änderungen geschrieben und dann direkt in die Zielsprache C übersetzt werden.

Am Python-Code muss nur eine einzige Anpassung vorgenommen werden. Dies ist das Hinzufügen von Typinformationen zu jeder Variablen. In der Regel sieht eine Variable in Python wie folgt aus:

x = 0.5

Nach dem Hinzufügen des Typs mit Cython wird diese Variable auf folgende Weise dargestellt:

cdef float x = 0.5

Ähnlich wie bei C sagt auch Cython, dass die Variable ein Gleitkomma ist. Bei reinem Python wird der Typ der Variablen spontan bestimmt. Durch die explizite Typdeklaration in Cython wird die Konvertierung nach C ermöglicht, da explizite Typdeklarationen + erforderlich sind. 

Um Cython zu installieren, wird nur eine einzige Pip-Zeile benötigt:

pip install cython

Typen in Cython

Man unterscheidet zwei verschiedene Typenreihen für Variablen und Funktionen in Cython.

Typen von Variablen sind:

  • cdef int a, b, c
  • cdef char *s
  • cdef float x = 0.5 (einfache Genauigkeit)
  • cdef double x = 63.4 (doppelte Genauigkeit)
  • cdef list names
  • cdef dict goals_for_each_play
  • cdef object card_deck

Es sollte darauf hingewiesen werden, dass alle diesen Typen aus C/C ++ stammen! 

Typen von Funktionen sind:

  • def — Grundsätzlich ist es Python. def-Funktion wird von Python aus aufgerufen.
  • cdef — Grundsätzlich ist es C. cdef-Funktion wird für Cython-Funktionen verwendet, die reine C-Funktionen sein sollen, und wird von C aus aufgerufen werden.
  • cpdef —kombiniert sowohl def- als auch cdef-Funktion, indem sie zwei Funktionen erstellt: die def-Funktion für den Python-Typ und die cdef-Funktion für den C-Typ. Sie kann also sowohl von Python als auch von C aus aufgerufen werden.

Nachdem man den Überblick über den Begriff und Typen in Cython bekommen hat, kann man fortfahren und die Beschleunigung implementieren!

Beschleunigung des Codes mit Cython

Der erste Schritt besteht darin, einen Python-Code-Benchmark einzurichten: Eine for-Schleife wird verwendet, um die Fakultät einer Zahl zu berechnen. Nachfolgend wird der rohe Python-Code dargestellt:

def test(x):
    y = 1
    for i in range(1, x+1):
        y *= i
    return y

Beachten Sie, dass der Cython-Äquivalent mit der gleichen Funktion auf ähnliche Weise dargestellt wird. Zunächst ist es jedoch notwendig, sicherzustellen, dass die Cython-Codedatei die Erweiterung .pyx hat. Die einzige Änderung wird am Code selbst vorgenommen, und zwar wird der Typ jeder Variablen und Funktion deklariert.

cpdef int test(int x):
    cdef int y = 1
    cdef int i
    for i in range(1, x+1):
        y *= i
    return y

Darüber hinaus muss man darauf achten, dass die Funktion cpdef verwendet wird, um sicherzustellen, dass sie von Python aus aufgerufen werden kann. Beachten Sie auch, wie sogar die Loop-Variable i einen Typ hat. Für alle Variablen in der Funktion muss der Typ festgelegt werden, was dem C-Compiler erleichtert zu verstehen, welchen Typ er verwenden soll!

Beim nächsten Schritt wird eine setup.py-Datei erstellt, deren Aufgabe es ist, den Cython-Code in C-Code zu kompilieren:

from distutils.core import setup
from Cython.Build import cythonize

setup(ext_modules = cythonize('run_cython.pyx'))

Dann wird das Kompilieren durchgeführt:

python setup.py build_ext --inplace

Man hat ein fertiges Ergebnis: Der C-Code wurde erfolgreich kompiliert und ist einsatzbereit!

Man kann sehen, dass sich im Ordner mit dem Cython-Code alle zum Ausführen von C-Code notwendigen Dateien befinden, darunter die run_cython.c -Datei. Bei Interesse kann man einen Blick darauf werfen, um den C-Code zu sehen, den Cython generiert hat!

Der neue, superschnelle C-Code ist fertig und kann getestet werden! Der nachfolgende Code implementiert einen Geschwindigkeitstest, mit dem der Python-Code mit dem Cython-Code verglichen werden kann.

import run_python
import run_cython
import time

number = 10

start = time.time()
run_python.test(number)
end =  time.time()

py_time = end - start
print("Python time = {}".format(py_time))

start = time.time()
run_cython.test(number)
end =  time.time()

cy_time = end - start
print("Cython time = {}".format(cy_time))

print("Speedup = {}".format(py_time / cy_time))

Wie man sieht ist der Code sehr einfach. Auf die gleiche Weise wie beim regulären Python werden die Dateien importiert und die Funktionen ausgeführt!

Cython liefert gute Möglichkeiten zur Beschleunigung für fast jeden  rohen Python-Code, ohne dass viel zusätzlicher Aufwand benötigt wird. Das Wichtigste ist, dass je mehr Schleifen man durchläuft und je mehr Daten man verarbeitet, desto besser kann Cython helfen.

Die nachfolgende Tabelle zeigt, wie viel Geschwindigkeit Cython für verschiedene Fakultätswerte gegeben hat. Mit Cython kann man über 36-fache Geschwindigkeitsbeschleunigung erreichen!

Number Python Time Cython Times Speedup
10 1.6689300537109375e-06 4.76837158203125e-07 3.5
100 3.337860107421875e-06 4.76837158203125e-07 7.0
1000 2.193450927734375e-05 9.5367431640625e-07 23.0
10000 0.0002090930938720703 6.4373016357421875e-06 32.481
100000 0.0021562576293945312 6.008148193359375e-05 35.89
1000000 0.02128767967224121 0.0005953311920166016 35.75
10000000 0.2148280143737793 0.00594782829284668 36.1187317112278

Sollten Sie weitere Fragen zu Cython haben, so können Sie sich an das Team von AI-United.de per Mail oder Q&A wenden.

Quelle
AI-United-Redaktion

Kommentar hinzufügen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.