C / C ++ zu Python Erweiterungsmodule schreiben

Verzeichnis

1 Einführung

1.1 Python Anwendungsmöglichkeiten und Vorteile der Erweiterungsmodule

1.2 Aufbau Erweiterungsprozess

2 setup.py-Skript

3 Funktionsschnittstelle, Parameterübergabe, einfach Wert zurückgeben

3.1 Funktionsschnittstelle

3.2 Parameterübergabe

3.3 einfacher Rückgabewert

4-Tupel, Listen, Wörterbücher, puffern

5 Ausnahmebehandlung, die Referenzzählung

5.1 löst eine Ausnahme

5.2 Referenzzähler

6 GIL und Multithreading

  1. kurze Einführung

Dieses Papier zeichnet die Entwicklung Python-Erweiterungsmodul in der Praxis verwendet wird, so dass der Leser niedrigen Kosten Python Erweiterungsmodule verwenden können, um die Anwendungsleistung zu verbessern.

Der Text wird nicht einführende Tutorial Module erweitert, sondern für eine bestimmte Idee von Erweiterungsmodulen, aber nicht gelungen ist es effektiv Leser anzuwenden.

1.1 Python Anwendungsmöglichkeiten und Vorteile der Erweiterungsmodule

Python-Erweiterungsmodule von mehreren gemeinsamen Anwendungsmöglichkeiten und Vorteile:

Leistungsverbesserungen

Python Erweiterungsmodul C / C ++ zu schreiben, unter Verwendung seine Leistung berechnen, ist C / C ++ das gleiche Niveau. Performance-Verlust auf sprachübergreifende Kommunikations-Schnittstelle auf ein vernachlässigbares klein ist, kann sie bieten eine sehr gute Leistung zu unterstützen. Typisch für solche Numpy Paket für wissenschaftliches Rechnen, die ihr zugrunde liegenden mathematischen Berechnungen Bibliotheken von Drittanbietern genannt, ist die Leistung auf dem gleichen Niveau.

Die Verwendung von Multi-Core-Rechenleistung

Durch die Steuerung der Ausdehnung des GIL, Rechenleistung kann auf Multi-Core-CPU verwendet wird, nicht beschränkt auf Einzelkern reine Programmgrenzen Python. Wie viele Multi-Thread-Kern kann auf den Einsatz angepasst werden.

Isolation und modulare Systemkomponenten

Die von jedem C / C ++ Funktion eine Python-Schnittstelle bereitstellt, die nicht zwischen der Funktion eines Staates gemeinsam genutzt wird, einen guten Satz up Isolation zu erreichen, trägt zur Entwicklung und Erprobung. Und weil alle Parameter von Python übergeben, leicht bedruckbar und unterbrochene debugability wurde stark verbessert.

Mit Bibliotheken von Drittanbietern

Nicht jede Bibliothek Python-Unterstützung hat, dann müssen Sie Ihre eigene Erweiterungsmodul für das Docking-System schreiben. Aber moderne populäre große Bibliothek hat viele offizielle Python-Erweiterungsmodule, so dass die Qualität der Anwendungen hat, wie OpenCV und typischen PyCUDA stark verbessert.

1.2 Aufbau Erweiterungsprozess

Schreiben setup.py: script Erweiterungsmodul Konfiguration Metainformationen

Führen Sie die notwendigen Header-Dateien: mehrere Header-Dateien verwendet hauptsächlich auf Python.h

Design Export-Funktion Tabelle: Exportieren von Python-Funktion Tabelle zu verwenden,

Initialisierung Funktionsbausteine: mehrere Initialisierungsschritte notwendig

  1. setup.py-Skript

setup.py Skripte werden verwendet, um die Konfiguration des Erweiterungsmoduls zu bauen. Es gibt viele Online-einfach ein Projekt praktische Beispiele gibt und sind wie folgt:

Importplattform

von distutils.core Import-Setup, Erweiterung

von distutils Import sysconfig

cfg_vars = sysconfig.get_config_vars ()

wenn 'OPT' in cfg_vars:

cfg_vars [ 'OPT'] = cfg_vars [ 'OPT'] ersetzen. ( '- Wstrict-Prototypen', '')

mod_expy = Extension ( 'libxx.expy',

Quellen = [ 'libxx / expy.c'],

Bibliotheken = [ 'jpeg',],

include_dirs = [ '/ opt / local / include',],

library_dirs = [ '/ opt / local / lib',],

define_macros = [( 'major_version', '1'), ( 'minor_version', '0')],

)

# Compiler zwischen den verschiedenen Plattformen zu unterscheiden

wenn platform.system () == 'Darwin':

os.environ [ 'ARCHFLAGS'] = '- Bogen x86_64'

extmodlist = [mod_expy,]

Elif platform.system () = 'Linux':

os.environ [ 'ARCHFLAGS'] = '- i386 Bogen -arch x86_64'

extmodlist = [mod_expy,]

sonst:

erhöhen Runtime ( 'Unknown System () =% s' % repr (platform.system ()))

setup (name = 'libxx',

version = '1.0',

Beschreibung = 'libxx-Python,

Autor = 'gashero',

author_email='[email protected]‘,

Pakete = [ 'libxx'],

ext_modules = extmodlist,

url = 'http: //example.com/',

long_description = 'xxxxxx xxxxxx',

)

Hallo Welt in Bezug auf die verschiedenen Ebenen der setup.py. Als das Skript praktische Funktionen hinzuzufügen:

Bietet eine umfassende Zusammenstellung Parameter wie spezifische Makrodefinitionen sind die Compiler-Parameter zusammengestellt,

Siehe andere Bibliotheken von Drittanbietern

Compile unterscheidet verschiedene Plattformen, Linux und Mac differenzierten

Champions League bietet Ihnen eine umfassende Meta-Informationen

Normalerweise haben wir geschrieben Erweiterung Modulgröße ist nicht groß, wie setup.py-Skript genug zu verwenden. Wenn es mit den Erweiterungsmodulen komplexe mehr Quelldateien kommt, nur um weiterhin die Erweiterungsobjekte zu erhöhen.

  1. Funktionsschnittstelle, Parameterübergabe, einfach Wert zurückgeben

3.1 Funktionsschnittstelle

Es wird verwendet, um die Funktion zu definieren und an den Python-Aufruf übergeben. Es ist die definierende Instanz PyMethodDef Typ. Es folgt ein Beispiel:

static PyMethodDef expyMethods [] = {

{ „Add“, expy_add, METH_VARARGS, „Add 2 Nummer“},

{NULL, NULL, 0, NULL}

};

Diese Definition der vier Felder im dritten Feld die Funktion aufzurufen entschieden, folgt gegebenenfalls als:

METH_VARARGS: eine Vielzahl von Parametern bilden, die am häufigsten play

METH_NOARGS: kein Parameter, zur Ausgabe von Klasse-Funktion verwendet

METH_VARARGS | METH_KEYWORDS: beide anonyme Parameter und Keyword-Argumente

Das letzte Feld ist die Funktion des Dokuments für die Hilfe () Funktion angezeigt wird.

3.2 Parameterübergabe

Die Funktion wird mit Hilfe der Parameter definiert die anonymen Schlüsselparameter enthalten, sind unterschiedlich, die beide der folgenden:

static PyObject * func (PyObject * Selbst, PyObject * args);

static PyObject * func (PyObject * Selbst, PyObject * args, PyObject kwargs **);

Wenn es wird kein entsprechender Inhalt NULL übergeben. Für Module Funktion, nicht der Objektmethode, können Sie nicht auf sich selbst konzentrieren.

Verwendung von PyArg_ParseTuple Auflösung Prozessparameter () und PyArg_ParseTupleAndKeywords (). Mit einer Zeichenfolge der Beschreibung der Parameterliste, dann die Referenzadresse jedes ankommenden Objekts.

In Anbetracht der Parameter und Rückgabewerttypen können sich nicht gegenseitig freundlich sein, und es wird allgemein empfohlen, nicht die Art von liefern:

Relevant numerischer Typ Architektur wie int, lang, aber die Länge des bekannten digitalen Übertragungsart

Struktur, weil der Ort der tatsächlichen Speicherstruktur kann Lebenszyklus haben, das gleiche gilt für C ++ Objekte

Adreßzeiger, weil die Architektur bezieht, Funktionszeiger umfassend

In der Tat, nach Bedarf der Adresse der Struktur passieren, wenn das Objekt im allgemeinen Schreib Objekten in Erweiterungsmodulen wird empfohlen, obwohl schwieriger, aber die Kompatibilität wird viel besser sein.

Überlassen Sie nichts in C / C ++ Programm, wie globale Variablen.

3.3 einfacher Rückgabewert

Rückgabewert der Funktion muss ein Python-Objekt sein.

Einfache Funktion gibt keinen Wert direkt am Ende einer Makrofunktion verwendet werden, erreicht:

Py_RETURN_NONE;

Diese einfache Ausgabefunktion ist das kein Problem.

Sie können ein wenig verwenden mehr kompliziert Py_BuildValue () Nachdem eine Zeichenfolge in jedem Format übergeben Werte beschrieben, auch komplexe Datenstrukturen aufgebaut werden.

  1. Tupeln, Listen, Wörterbücher, Puffer

Die Rolle von Tupeln in Python ist unveränderlich, die für den Inhalt Python ist sehr freundlich, und die Leistung ist besser als eine Liste.

Der Wert der Liste ist, dass es nicht Inhaltsspeicher Länge fixiert werden kann. Zum Beispiel wird das Rück C / C ++ Bibliothek vieler fremden Inhalte in einer iterativen Art und Weise verwendet. Zu Beginn der Funktion nicht weiß, wie viele Objekte der Lage sind, zurückzukehren, nur neben jeden Anruf das nächste Objekt zu erhalten. In diesem Fall ist es für das Erstellen einer Liste geeignet ist, wird jedes Element dann mit append () Methode zugegeben. Zum Beispiel:

PyObject * retlist = PyList_New (0); // schaffen eine Warteschlangenlänge 0

while (po) {

PyList_Append (retlist, Py_BuildValue ( "{}"));

pos = Mög-> weiter;

}

Wörterbuch kann auch verwendet werden, um den Inhalt einer einzigen Struktur zurückzukehren. Es ist etwa C / C ++ Struktur jeden Feldes als ein Element, das Wörterbuch und zurück zu setzen. Ablesbarkeit diesen Ansatz wird gut sein.

Beispiele für die Verwendung von dict Speichern von Informationen, Schlüsselzeichenfolge:

PyObject * fmtinfo = PyDict_New ();

PyDict_SetItemString(fmtinfo, “index”, PyInt_FromLong(1));

Es ist nicht die Liste des dict zurückzukehren, schließlich empfohlen, mehr Leistung verbrauchen. Für die Rück Vielzahl von Strukturen, eine geeignetere Art und Weise in der Liste oder Tupel.

Verwendung Py_BuildValue (Inhaltslänge geschätzt, dass die Rückkehr) besser geeignet.

Für den Inhalt nicht von String-Puffertypen müssen verstehen, verwendet werden kann, und die Leistung wäre mehr als str speichert Speichertyp. str Unterschied in Bezug auf die Art des Puffertypen ist, Systempuffer nicht den Inhalt der gleichen zwei Strings überprüfen. Und str System wird dafür sorgen, wird es keine Wiederholung der Zeichenfolge sein. Diese Berechnung ist zeitaufwendig zu sein.

Nach dem neuen Puffer, um ein Zeiger seine Betriebe Beispiele zu erhalten:

Py_ssize_t buflen = 1000, _buflen;

void * BUFPTR;

PyObject * buf = PyBuffer_New (buflen);

if (PyObject_AsWriteBuffer (buf, & BUFPTR & _buflen) <0) {

NULL zurück;

}

  1. Ausnahmebehandlung der Referenzzähler

5.1 löst eine Ausnahme

Gebrauchte Python zu benachrichtigen, ist ein Fehler aufgetreten in einer Funktion. häufigsten verwendet integrierte Ausnahmen mehr:

PyExc_ZeroDivisionError: von 0

PyExc_IOError: IO-Fehler

PyExc_TypeError: die Art des Fehlers, wie beispielsweise die falsche Art von Parametern

PyExc_ValueError: error Wertebereich

PyExc_RuntimeError: Laufzeitfehler

PyExc_OSError: Fehler, wenn sie mit verschiedenen OS der Interaktion

Sie können eine Ausnahme von einer Vielzahl von Designs werfen. Die tatsächliche Methode gibt eine Ausnahme aus, wie zum Beispiel:

if (ret <0) {

PyErr_SetString (PyExc_RuntimeError, „failed Runtime!“);

NULL zurück;

}

Manchmal hoffe ich geworfen Ausnahme enthält einige Parameter, wie zB Fehlercodes, um eine bessere Fehlersuche zu erleichtern. Sie können die folgende Methode verwenden:

if (ret <0) {

PyErr_Format (PyExc_OSError „Fehler [% d] =% s“,

errno, strerror (errno));

}

Eine Vielzahl von C / C ++ Bibliothek macht ausgiebig Gebrauch von dem falschen Code, verwenden, so das oben beschriebene Verfahren ist weit verbreitet. Siehe Ausnahmen Funktionsfehler in Python geworfen und enthält der Fehlercode üblich ist reine C / C ++ Programm zu schreiben, den Absturz zu bewegen und schöner machen. Der Prozess Erweiterungsmodule des Schreibens macht diese Arbeit standardisiert.

5.2 Referenzzähler

Erweiterte Referenzzähler ist sehr magisch, und es ist ein Problem, kritisiert Modul.

Die tatsächliche Nutzung, jeder Python-API zeigt ihren Betrieb auf dem Referenzzähler im Dokument. Kreditaufnahme ist nicht die Änderung der Referenzzähler und die Referenz 1 zu erhöhen.

Um zu vermeiden, jedes Mal, Übelkeit zum Inhalt zu finden, könnte einige freundlichen Funktionen nutzen. Zum Beispiel Py_BuildValue () direkt mit C / C ++ Daten übergeben, in dem zum Erzeugen von komplexen Datenstrukturen zuständig ist, und den Referenzzähler verwalten.

Tupel, Referenzzähler-Management ist auch einfacher als die Liste Puffer, sollte str empfohlen werden.

  1. GIL und Multithreading

Python GIL ist, die Verwendung von Multi-Core direkter Ursache zu begrenzen, ist die Ursache interner Python Interpreter einige globalen Variablen hat, wie beispielsweise die typische Ausnahmebehandlung. Und es gibt viele Module von Drittanbietern in der Python-API und nutzen diese globale Variablen, die nicht verbessert werden kann GIL wurden Fortschritte erzielt.

Level im Erweiterungsmodul sind der GIL freigegeben, so dass die CPU der Steuerung zurück zum Python und die aktuellen C / C ++ Code kann auch fortgesetzt werden. Aber es ist wichtig zu beachten, dass jede Python API aufrufen muss unter der Kontrolle von GIL durchgeführt werden. So lösen GIL vor rechenintensive Aufgaben durchführen, die nach Abschluss der Berechnung erneut bewerben GIL, dann den Rückgabewert und die Ausnahmebehandlung.

Die erste Anwendung für die Freigabe und GIL in der Funktionserweiterungsmodul geschrieben in:

PyObject statisch * fun (PyObject * Selbst, PyObject * args) {

// ...

PyThreadState * _save;

_save = PyEval_SaveThread ();

Block();

PyEval_RestoreThread (_save);

// ...

}

Das Verfahren muss auch Anruf während Modulinitialisierung PyEval_InitThreads ().

Eine andere Methode ist einfach und mehr:

Py_BEGIN_ALLOW_THREADS;

// potenziell Sperrbetrieb

Py_END_ALLOW_THREADS;

Daher ist eine einfache Methode ist, Multi-Core-Computing zu verwenden, die geteilte Aufgabe in eine Vielzahl von kleinen Teilen, wobei jedes der Kleinteile wird in einem laufenden Faden angeordnet. Thread ruft die Funktion Erweiterungsmodul zu berechnen, berechnen Funktion gibt die GIL eigentliche Berechnung.

Auf diese Weise können Sie effektiv Python Threads zu verwalten, ohne die Verwendung von pthread solche Probleme in C / C ++, die nur Notwendigkeit, die einfachsten Rechen ganz gut zu tun.

Veröffentlicht 261 Originalarbeiten · erntete Lob 4 · Aufrufe 4263

Ich denke du magst

Origin blog.csdn.net/it_xiangqiang/article/details/105206265
Empfohlen
Rangfolge