28.08.2017: Der im Kommentar erwähnte Teil wurde korrigiert.
Kürzlich habe ich versucht, durch die Implementierung einer langsamen Verarbeitung in Python in C mit Cython zu beschleunigen. Daher werde ich diese zusammenfassen, damit ich zurückblicken kann, wenn ich vergesse, wie es geht. ** Es werden nur super rudimentäre und oberflächliche Dinge geschrieben **
Cython erkennt, dass es so ist, als würde man eine in C geschriebene Funktion vermitteln, damit sie von Python aus aufgerufen werden kann. Mit anderen Worten, es ist ein Bild, das Sie jeden guten Punkt verwenden können, indem Sie den Teil für langsame Ausführung in C implementieren und den anderen Teil einfach in Python zeichnen.
windows Gehen Sie zu dieser Site und laden Sie die entsprechende Version herunter. (Wenn der Teil von cp ○○ Python 3.6 ist, wählen Sie den Teil aus, der 36 ist.) Geben Sie an der Eingabeaufforderung "pip install the path of the downloaded file" ein, um die Installation zu starten.
Wenn Sie danach einen Fehler wie "Fehler: vcvarsall.bat" kann nicht gefunden werden, rufen Sie die folgende Referenzseite auf [Einstellungen zur Verwendung einer anderen Version von VC ++] Es wurde gelöst, indem auf / build-python-package-on-windows / # VC-2) verwiesen wurde.
Referenzseite https://www.regentechlog.com/2014/04/13/build-python-package-on-windows/
Ich denke, Sie können es mit $ pip install cython
installieren.
-. c-Datei: Eine Datei, die die Implementierung in C-Sprache beschreibt
Um zu erkennen, dass es schneller ist, verwenden wir diesmal den folgenden Code mit double for loop.
python_code.py
# -*-encode: utf-8-*-
import time
if __name__ == "__main__":
start_t = time.time()
arr_a = [i for i in range(1000)]
arr_b = [i for i in range(1000)]
res = 0
for elem_a in arr_a:
for elem_b in arr_b:
res = res + elem_a + elem_b
print(res)
all_time = time.time() - start_t
print("Execution time:{0} [sec]".format(all_time))
Wir finden nur die Summe der Summen aller Kombinationen der Arrays "arr_a" und "arr_b". Wenn Sie dies tun,
out[1]
999000000
Execution time:0.24517321586608887 [sec]
Es wird.
Python scheint also eine lange Zeit für die Schleife zu brauchen
for elem_a in arr_a:
for elem_b in arr_b:
res = res + elem_a + elem_b
Dieser Teil ist in der Sprache C implementiert. Die Header-Datei und der Quellcode lauten wie folgt.
cython_c_code.h
#ifndef CYTHON_CODE
#define CYTHON_CODE
int c_algo(int*, int*, int, int);
#endif
cython_c_code.c
#include "cython_c_code.h"
int c_algo(int *arr_a, int *arr_b, int size_a, int size_b){
int res = 0;
for(int i=0; i < size_a; i++){
for(int j=0; j < size_b; j++){
res = res + arr_a[i]+arr_b[j];
}
}
return res;
}
Schreiben Sie die obige C-Funktion c_algo ()
in .pyx, damit sie in Python aufgerufen werden kann.
cython_pyx_code.pyx
cimport numpy as np
cdef extern from "cython_c_code.h":
int c_algo(int *arr_a, int *arr_b, int size_a, int size_b)
def cy_algo(np.ndarray[int, ndim=1] arr_a, np.ndarray[int, ndim=1] arr_b):
return c_algo(&arr_a[0], &arr_b[0], len(arr_a), len(arr_b))
Der hier angezeigte cimport
ist eine Anweisung zum Lesen der Cython-Version der Header-Datei.
Mit anderen Worten, indem Sie "python cimport numpy as np" schreiben, können Sie Typen wie "np.ndarray" deklarieren.
Abgesehen davon, wenn Sie auch eine Numpy-Funktion benötigen, benötigen Sie auch "Numpy importieren".
Beschreiben Sie als Nächstes die zu verwendende Funktion aus der C-Header-Datei.
cdef extern vom Namen der Header-Datei:
Zu verwendende Funktion
Beschreiben Sie auf diese Weise.
Beschreiben Sie abschließend die Funktion, die von der Python-Seite aufgerufen werden soll.
Es wird in def
wie Python beschrieben, aber der Typ wird im Argumentteil angegeben.
Der Typ beim Empfang eines Numpy-Arrays als Argument ist "np.ndarray [Elementtyp, ndim = Anzahl der Dimensionen]".
Wenn ein Array-Zeiger an eine C-Funktion übergeben wird, kann er auch mit & array name [0]
übergeben werden.
setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize
import numpy as np
sourcefiles = ['cython_pyx_code.pyx','cython_c_code.c']
setup(
cmdclass = {'build_ext': build_ext},
ext_modules = [Extension("cython_code", sourcefiles, include_dirs=[np.get_include()])],
)
Importieren Sie die erforderliche Bibliothek und schreiben Sie Folgendes in das Argument "ext_modules" von "setup ()".
[Erweiterung (" Name dieser Bibliothek ", [zu verwendende Quelldateien], include_dirs = [Header der zu verwendenden Bibliothek])]
Da wir dieses Mal numpy verwenden, übergeben Sie np.get_include ()
an include_dirs
.
Kompilieren Sie mit $ python setup.py build_ext -i
.
Wenn alles gut geht, haben Sie ein Build-Verzeichnis und einen "Bibliotheksnamen.so" (".pyd" für Windows). Sie können es wie eine normale Python-Bibliothek importieren und verwenden.
cython_py_code.py
# -*-encode: utf-8-*-
import time
import numpy as np
import cython_code
if __name__ == "__main__":
start_t = time.time()
arr_a = [i for i in range(1000)]
arr_b = [i for i in range(1000)]
res = cython_code.cy_algo(np.array(arr_a), np.array(arr_b))
print(res)
all_time = time.time() - start_t
print("Execution time:{0} [sec]".format(all_time))
out[2]
999000000
Execution time:0.0010039806365966797 [sec]
Die Geschwindigkeit hat sich um das 245-fache verbessert.
Sie können den Code auch direkt in die .pyx-Datei schreiben, indem Sie den Typ angeben.
cy_only.pyx
cimport numpy as np
def cy_algo(np.ndarray[int, ndim=1] arr_a, np.ndarray[int, ndim=1] arr_b):
cdef int res
cdef int elem_a
cdef int elem_b
res = 0
for elem_a in arr_a:
for elem_b in arr_b:
res = res + elem_a +elem_b
return res
Alle auf diese Weise verwendeten Variablen werden durch "cdef type name variable name" definiert. Beachten Sie, dass sich die Ausführungsgeschwindigkeit verlangsamt, wenn Sie zunächst vergessen, "elem_a" und "elem_b" zu definieren. Wenn Sie dies kompilieren und von Python aus aufrufen,
out[3]
999000000
Execution time:0.10053086280822754 [sec]
Es ist ungefähr doppelt so schnell, aber es scheint langsamer zu sein als das Schreiben in C, da es einfach ist, wie Python zu schreiben.
Da im Kommentar darauf hingewiesen wurde, habe ich den Code wie folgt geändert.
cy_only.pyx
cimport numpy as np
def cy_algo(np.ndarray[int, ndim=1] arr_a, np.ndarray[int, ndim=1] arr_b):
cdef int res = 0
cdef size_t len_a = len(arr_a)
cdef size_t len_b = len(arr_b)
for i in range(len_a):
for j in range(len_b):
res = res + arr_a[i] +arr_b[j]
return res
Dann,
out[4]
999000000
Execution time:0.0019919872283935547 [sec]
Die Geschwindigkeit war nahe an der in C geschriebenen. Cython Es stellte sich heraus, dass selbst solides Schreiben schneller wäre, wenn es richtig geschrieben würde.
Ich fange gerade an, Cython zu berühren, und ich verstehe nur die Einführungsstufe, also habe ich vielleicht etwas Passendes geschrieben. Ich würde es begrüßen, wenn Sie in diesem Fall darauf hinweisen könnten.
Es scheint, dass die Geschwindigkeit weiter verbessert wird, indem unnötige Optionen in setup.py
deaktiviert werden.
Eine Liste finden Sie unter hier.
Wenn Sie es etwas besser verstehen können, kann ich diesen Artikel umschreiben, um das Lesen zu erleichtern.
Recommended Posts