Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel erstellen Sie ein C++-Erweiterungsmodul für CPython, um einen hyperbolischen Tangens zu berechnen und ihn aus Python-Code aufzurufen. Die Routine wird zuerst in Python implementiert, um den relativen Leistungsgewinn der Implementierung derselben Routine in C++ zu veranschaulichen.
Codemodule, die in C++ (oder C) geschrieben wurden, werden häufig verwendet, um die Funktionen eines Python-Interpreters zu erweitern. Es gibt drei haupttypen von Erweiterungsmodulen:
- Beschleunigermodule: Ermöglichen eine gesteigerte Leistung. Da Python eine interpretierte Sprache ist, können Sie ein Beschleunigermodul in C++ schreiben, um die Leistung zu steigern.
- Wrappermodule: Machen Sie vorhandene C/C++-Schnittstellen für Python-Code verfügbar oder machen Sie eine pythonähnliche API verfügbar, die von Python einfach zu verwenden ist.
-
Module auf niedriger Ebene für den Systemzugriff: Erstellen Sie Systemzugriffsmodule, um Features auf niedrigerer Ebene der
CPython
Laufzeit, des Betriebssystems oder der zugrunde liegenden Hardware zu erreichen.
In diesem Artikel werden zwei Möglichkeiten zum Bereitstellen eines C++-Erweiterungsmoduls für Python veranschaulicht:
- Verwenden Sie die Standarderweiterungen
CPython
, wie in der Python-Dokumentation beschrieben. - Verwenden Sie PyBind11, was wir aufgrund ihrer Einfachheit für C++11 empfehlen. Um die Kompatibilität sicherzustellen, stellen Sie sicher, dass Sie mit einer der neueren Versionen von Python arbeiten.
Das vollständige Beispiel für diese exemplarische Vorgehensweise ist auf GitHub unter python-samples-vs-cpp-extension verfügbar.
Voraussetzungen
Visual Studio 2017 oder höher mit den installierten Python-Entwicklungstools. Die Workload enthält die nativen Python-Entwicklungstools, die die C++-Workload und Toolsets hinzufügen, die für systemeigene Erweiterungen erforderlich sind.
Weitere Informationen zu den Installationsoptionen finden Sie unter Installieren der Python-Unterstützung für Visual Studio.
Hinweis
Wenn Sie die Workload von Data Science und analytischen Anwendungen installieren, werden Python und die Option für native Python-Entwicklungstools standardmäßig installiert.
Wenn Sie Python separat installieren, müssen Sie die Option "Debuggingsymbole herunterladen " unter "Erweiterte Optionen " im Python-Installationsprogramm auswählen. Diese Option ist erforderlich, um das Debuggen im gemischten Modus zwischen Ihrem Python-Code und systemeigenem Code zu verwenden.
Erstellen der Python-Anwendung
Führen Sie die folgenden Schritte aus, um die Python-Anwendung zu erstellen.
Erstellen Sie ein neues Python-Projekt in Visual Studio, indem Sie Datei>Neu>Projekt auswählen.
Suchen Sie im Dialogfeld " Neues Projekt erstellen " nach Python. Wählen Sie die Python-Anwendungsvorlage und dann "Weiter" aus.
Geben Sie einen Projektnamen und einen Speicherort ein, und wählen Sie "Erstellen" aus.
Visual Studio erstellt das neue Projekt. Das Projekt wird im Projektmappen-Explorer geöffnet, und die Projektdatei (.py) wird im Code-Editor geöffnet.
Fügen Sie in der datei .py den folgenden Code ein. Um einige der Python-Bearbeitungsfeatures zu erleben, versuchen Sie, den Code manuell einzugeben.
Dieser Code berechnet einen hyperbolischen Tangens, ohne die mathematische Bibliothek zu verwenden, und es ist das, was Sie später mit python nativen Erweiterungen beschleunigen.
Tipp
Schreiben Sie Ihren Code in reinem Python, bevor Sie ihn in C++ neu schreiben. Auf diese Weise können Sie einfacher überprüfen, um sicherzustellen, dass Ihr systemeigener Python-Code korrekt ist.
from random import random from time import perf_counter # Change the value of COUNT according to the speed of your computer. # The value should enable the benchmark to complete in approximately 2 seconds. COUNT = 500000 DATA = [(random() - 0.5) * 3 for _ in range(COUNT)] e = 2.7182818284590452353602874713527 def sinh(x): return (1 - (e ** (-2 * x))) / (2 * (e ** -x)) def cosh(x): return (1 + (e ** (-2 * x))) / (2 * (e ** -x)) def tanh(x): tanh_x = sinh(x) / cosh(x) return tanh_x def test(fn, name): start = perf_counter() result = fn(DATA) duration = perf_counter() - start print('{} took {:.3f} seconds\n\n'.format(name, duration)) for d in result: assert -1 <= d <= 1, " incorrect values" if __name__ == "__main__": print('Running benchmarks with COUNT = {}'.format(COUNT)) test(lambda d: [tanh(x) for x in d], '[tanh(x) for x in d] (Python implementation)')
Führen Sie das Programm aus, indem Sie Debug>Start ohne Debugging auswählen oder die Tastenkombination STRG+F5 verwenden.
Ein Befehlsfenster wird geöffnet, um die Programmausgabe anzuzeigen.
Achten Sie in der Ausgabe darauf, wie viel Zeit für den Benchmark-Prozess verbracht wurde.
Für diese exemplarische Vorgehensweise sollte der Benchmarkprozess ungefähr 2 Sekunden dauern.
Passen Sie bei Bedarf den Wert der
COUNT
Variablen im Code an, damit der Benchmark in etwa 2 Sekunden auf Ihrem Computer abgeschlossen werden kann.Führen Sie das Programm erneut aus, und bestätigen Sie, dass der geänderte
COUNT
Wert den Benchmark in etwa 2 Sekunden erzeugt.
Tipp
Wenn Sie Benchmarks ausführen, verwenden Sie immer Debug>Ohne Debugging starten. Diese Methode trägt dazu bei, den Aufwand zu vermeiden, der beim Ausführen des Codes im Visual Studio-Debugger auftreten kann.
Erstellen der C++-Kernprojekte
Führen Sie die folgenden Schritte aus, um zwei identische C++-Projekte, Superfastcode und Superfastcode2 zu erstellen. Später verwenden Sie in jedem Projekt einen anderen Ansatz, um den C++-Code für Python verfügbar zu machen.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektmappennamen, und wählen Sie "Neues Projekt> aus.
Eine Visual Studio-Lösung kann sowohl Python- als auch C++-Projekte enthalten, was einer der Vorteile der Verwendung von Visual Studio für die Python-Entwicklung ist.
Legen Sie im Dialogfeld "Neues Projekt hinzufügen" den Sprachfilter auf C++ fest, und geben Sie im Suchfeldleer ein.
Wählen Sie in der Liste der Projektvorlagenergebnisse " Leeres Projekt" und dann "Weiter" aus.
Geben Sie im Dialogfeld " Neues Projekt konfigurieren " den Projektnamen ein:
- Geben Sie für das erste Projekt den Namen superfastcode ein.
- Geben Sie für das zweite Projekt den Namen superfastcode2 ein.
Wählen Sie "Erstellen" aus.
Wiederholen Sie diese Schritte, und erstellen Sie zwei Projekte.
Tipp
Ein alternativer Ansatz ist verfügbar, wenn Sie die nativen Python-Entwicklungstools in Visual Studio installiert haben. Sie können mit der Python-Erweiterungsmodulvorlage beginnen, die viele der in diesem Artikel beschriebenen Schritte vorab abgeschlossen hat.
Um das Erweiterungsmodul Schritt für Schritt zu erstellen, empfiehlt es sich in der Schritt-für-Schritt-Anleitung dieses Artikels, mit einem leeren Projekt zu beginnen. Nachdem Sie den Prozess verstanden haben, können Sie die alternative Vorlage verwenden, um Zeit zu sparen, wenn Sie ihre eigenen Erweiterungen schreiben.
Hinzufügen einer C++-Datei zum Projekt
Fügen Sie als Nächstes jedem Projekt eine C++-Datei hinzu.
Erweitern Sie im Projektmappen-Explorer das Projekt, klicken Sie mit der rechten Maustaste auf den Knoten "Quelldateien", und wählen Sie "Neues Element> aus.
Wählen Sie in der Liste der Dateivorlagen C++-Datei (.cpp) aus.
Geben Sie den Namen für die Datei als module.cpp ein, und wählen Sie dann "Hinzufügen" aus.
Von Bedeutung
Stellen Sie sicher, dass der Dateiname die .cpp Erweiterung enthält. Visual Studio sucht nach einer Datei mit der .cpp Erweiterung, um die Anzeige der C++-Projekteigenschaftenseiten zu ermöglichen.
Erweitern Sie auf der Symbolleiste das Dropdownmenü " Konfiguration ", und wählen Sie ihren Zielkonfigurationstyp aus:
- Aktivieren Sie für eine 64-Bit-Python-Laufzeit die x64-Konfiguration .
- Aktivieren Sie für eine 32-Bit-Python-Laufzeit die Win32-Konfiguration .
Wiederholen Sie diese Schritte für beide Projekte.
Konfigurieren von Projekteigenschaften
Konfigurieren Sie vor dem Hinzufügen von Code zu den neuen C++-Dateien die Eigenschaften für jedes C++-Modulprojekt, und testen Sie die Konfigurationen, um sicherzustellen, dass alles funktioniert.
Sie müssen die Projekteigenschaften für die Debug- und Releasebuildkonfigurationen jedes Moduls festlegen.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das C++-Modulprojekt (Superfastcode oder Superfastcode2), und wählen Sie "Eigenschaften" aus.
Konfigurieren Sie die Eigenschaften für den Debugbuild des Moduls, und konfigurieren Sie dann die gleichen Eigenschaften für den Releasebuild :
Konfigurieren Sie oben im Dialogfeld " Eigenschaftenseiten " des Projekts die folgenden Dateikonfigurationsoptionen:
Wählen Sie für die Konfiguration"Debuggen " oder "Freigeben" aus. (Möglicherweise werden diese Optionen mit dem Präfix "Aktiv " angezeigt.)
Wählen Sie für die Plattform je nach Auswahl im vorherigen Schritt "Aktiv" (x64) oder "Aktiv" (Win32) aus.
Hinweis
Wenn Sie eigene Projekte erstellen, sollten Sie die Debug - und Releasekonfigurationen separat gemäß Ihren spezifischen Szenarioanforderungen konfigurieren. In dieser Übung legen Sie die Konfigurationen so fest, dass ein Releasebuild von CPython verwendet wird. Diese Konfiguration deaktiviert einige Debugfeatures der C++-Laufzeit, einschließlich Assertionen. Für die Verwendung von CPython-Debug-Binärdateien (python_d.exe) sind unterschiedliche Einstellungen erforderlich.
Legen Sie andere Projekteigenschaften wie in der folgenden Tabelle beschrieben fest.
Um einen Eigenschaftswert zu ändern, geben Sie einen Wert in das Eigenschaftenfeld ein. Bei einigen Feldern können Sie den aktuellen Wert auswählen, um ein Dropdownmenü mit Auswahlmöglichkeiten zu erweitern oder ein Dialogfeld zu öffnen, um den Wert zu definieren.
Nachdem Sie Werte auf einer Registerkarte aktualisiert haben, wählen Sie "Übernehmen" aus, bevor Sie zu einer anderen Registerkarte wechseln. Mit dieser Aktion können Sie sicherstellen, dass Ihre Änderungen beibehalten werden.
Registerkarte und Abschnitt Eigentum Wert Konfigurationseigenschaften>Allgemein Zielname Geben Sie den Namen des Moduls an, damit es in Python-Anweisungen ` from...import
` wie `superfastcode` darauf verwiesen werden kann. Sie verwenden diesen Namen im C++-Code, wenn Sie das Modul für Python definieren. Wenn Sie den Namen des Projekts als Modulnamen verwenden möchten, behalten Sie den Standardwert von $<ProjectName> bei. Fügen Siepython_d.exe
am Ende des Namens von_d
hinzu.Konfigurationstyp Dynamische Bibliothek (.dll) Konfigurationseigenschaften>Fortgeschritten Zieldateierweiterung .pyd (Python Extension Module) C/C++>Allgemein Weitere Includeverzeichnisse Fügen Sie den Python-Include-Ordner entsprechend ihrer Installation hinzu (z. B. c:\Python36\include). C/C++>Präprozessor Präprozessordefinitionen Wenn es vorhanden ist, ändern Sie den _DEBUG Wert in NDEBUG , um der Nichtdebug-Version von CPython zu entsprechen. Wenn Sie python_d.exeverwenden, lassen Sie diesen Wert unverändert. C/C++>Codegenerierung Laufzeitbibliothek Multithread-DLL (/MD) zur Übereinstimmung mit der Veröffentlichungsversion (Nicht-Debug) von CPython. Wenn Sie python_d.exeverwenden, behalten Sie diesen Wert als Multithreaded Debug DLL (/MDd) bei. Grundlegende Laufzeitüberprüfungen Vorgabe Linker>Allgemein Zusätzliche Bibliotheksverzeichnisse Fügen Sie den Ordner "Python libs ", der LIB-Dateien enthält, entsprechend ihrer Installation hinzu (z. B. c:\Python36\libs). Verweisen Sie unbedingt auf den Ordner "libs ", der LIB-Dateien enthält, und nicht auf den Ordner "Lib ", der .py Dateien enthält. Von Bedeutung
Wenn die Registerkarte C/C++ nicht als Option für die Projekteigenschaften angezeigt wird, enthält das Projekt keine Codedateien, die Visual Studio als C/C++-Quelldateien identifiziert. Diese Bedingung kann auftreten, wenn Sie eine Quelldatei ohne C- oder .cpp Dateierweiterung erstellen.
Wenn Sie beim Erstellen der C++-Datei versehentlich "module.coo " anstelle von module.cpp eingegeben haben, erstellt Visual Studio die Datei, legt den Dateityp jedoch nicht auf C/C+ Compiler fest. Dieser Dateityp ist erforderlich, um das Vorhandensein der Registerkarte "C/C++"-Eigenschaften im Dialogfeld "Projekteigenschaften" zu aktivieren. Die Falschidentifizierung bleibt auch dann bestehen, wenn Sie die Codedatei mit einer .cpp Dateierweiterung umbenennen.
Um den Codedateityp ordnungsgemäß festzulegen, klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf die Codedatei, und wählen Sie "Eigenschaften" aus. Wählen Sie für den Elementtypden C/C++-Compiler aus.
Nachdem Sie alle Eigenschaften aktualisiert haben, wählen Sie "OK" aus.
Wiederholen Sie die Schritte für die andere Buildkonfiguration.
Testen Sie Ihre aktuelle Konfiguration. Wiederholen Sie die folgenden Schritte für die Debug- und Release-Builds beider C++-Projekte.
Legen Sie auf der Visual Studio-Symbolleiste die Buildkonfiguration auf "Debuggen " oder "Release" fest:
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das C++-Projekt, und wählen Sie "Erstellen" aus.
Die PYD-Dateien befinden sich im Projektmappenordner , unter "Debuggen " und " Release" und nicht im C++-Projektordner selbst.
Hinzufügen von Code und Testkonfiguration
Jetzt können Sie Ihren C++-Dateien Code hinzufügen und den Releasebuild testen.
Öffnen Sie für das Superfastcode-C ++-Projekt die module.cpp Datei im Code-Editor.
Fügen Sie in der datei module.cpp den folgenden Code ein:
#include <Windows.h> #include <cmath> const double e = 2.7182818284590452353602874713527; double sinh_impl(double x) { return (1 - pow(e, (-2 * x))) / (2 * pow(e, -x)); } double cosh_impl(double x) { return (1 + pow(e, (-2 * x))) / (2 * pow(e, -x)); } double tanh_impl(double x) { return sinh_impl(x) / cosh_impl(x); }
Speichern Sie Ihre Änderungen.
Erstellen Sie die Releasekonfiguration für das C++-Projekt, um zu bestätigen, dass Ihr Code korrekt ist.
Wiederholen Sie die Schritte zum Hinzufügen von Code zur C++-Datei für das Superfastcode2-Projekt , und testen Sie den Releasebuild .
Konvertieren von C++-Projekten in Python-Erweiterungen
Um die C++-DLL zu einer Erweiterung für Python zu machen, ändern Sie zuerst die exportierten Methoden für die Interaktion mit Python-Typen. Fügen Sie dann eine Funktion hinzu, um das Modul zusammen mit Definitionen für die Methoden des Moduls zu exportieren.
In den folgenden Abschnitten wird veranschaulicht, wie Sie die Erweiterungen mithilfe der CPython-Erweiterungen und pyBind11 erstellen. Das Superfasctcode-Projekt verwendet die CPython-Erweiterungen und das Superfasctcode2-Projekt implementiert PyBind11.
Verwenden von CPython-Erweiterungen
Weitere Informationen zum in diesem Abschnitt dargestellten Code finden Sie im Python/C API-Referenzhandbuch, insbesondere auf der Seite "Module Objects ". Wenn Sie den Referenzinhalt überprüfen, stellen Sie sicher, dass Sie Ihre Python-Version in der Dropdownliste oben rechts auswählen.
Öffnen Sie für das Superfastcode-C ++-Projekt die module.cpp Datei im Code-Editor.
Fügen Sie oben in der datei module.cpp eine Anweisung hinzu, um die Python.h-Headerdatei einzuschließen:
#include <Python.h>
Ersetzen Sie den
tanh_impl
Methodencode, um Python-Typen zu akzeptieren und zurückzugeben (d. r.: aPyObject*
):PyObject* tanh_impl(PyObject* /* unused module reference */, PyObject* o) { double x = PyFloat_AsDouble(o); double tanh_x = sinh_impl(x) / cosh_impl(x); return PyFloat_FromDouble(tanh_x); }
Fügen Sie am Ende der Datei eine Struktur hinzu, um zu definieren, wie die C++
tanh_impl
-Funktion in Python dargestellt wird:static PyMethodDef superfastcode_methods[] = { // The first property is the name exposed to Python, fast_tanh // The second is the C++ function with the implementation // METH_O means it takes a single PyObject argument { "fast_tanh", (PyCFunction)tanh_impl, METH_O, nullptr }, // Terminate the array with an object containing nulls { nullptr, nullptr, 0, nullptr } };
Fügen Sie eine weitere Struktur hinzu, um zu definieren, wie auf das Modul in Ihrem Python-Code verwiesen wird, insbesondere wenn Sie die
from...import
Anweisung verwenden.Der in diesem Code importierte Name sollte mit dem Wert in den Projekteigenschaften unter"Allgemeiner>Zielname der >" übereinstimmen.
Im folgenden Beispiel bedeutet der
"superfastcode"
Name, dass Sie diefrom superfastcode import fast_tanh
Anweisung in Python verwenden können, dafast_tanh
sie innerhalbsuperfastcode_methods
definiert ist. Dateinamen, die für das C++-Projekt intern sind, z. B. module.cpp, sind inkonsequent.static PyModuleDef superfastcode_module = { PyModuleDef_HEAD_INIT, "superfastcode", // Module name to use with Python import statements "Provides some functions, but faster", // Module description 0, superfastcode_methods // Structure that defines the methods of the module };
Fügen Sie eine Methode hinzu, die Python aufruft, wenn das Modul geladen wird. Der Methodenname muss sein
PyInit_<module-name>
, wobei <der Modulname> exakt der Eigenschaft "Konfigurationseigenschaften>"> des C++-Projekts entspricht. Das heißt, der Methodenname entspricht dem Dateinamen der vom Projekt erstellten PYD-Datei .PyMODINIT_FUNC PyInit_superfastcode() { return PyModule_Create(&superfastcode_module); }
Erstellen Sie das C++-Projekt, und überprüfen Sie Den Code. Wenn Fehler auftreten, lesen Sie den Abschnitt "Problembehandlung bei Kompilierungsfehlern" .
Verwenden von PyBind11
Wenn Sie die Schritte im vorherigen Abschnitt für das Superfastcode-Projekt ausführen, könnten Sie feststellen, dass die Übung Boilerplate-Code erfordert, um die Modulstrukturen für C++-CPython-Erweiterungen zu erstellen. In dieser Übung entdecken Sie, dass PyBind11 den Codierungsprozess vereinfacht. Sie verwenden Makros in einer C++-Headerdatei, um dasselbe Ergebnis zu erzielen, aber mit viel weniger Code. Zusätzliche Schritte sind jedoch erforderlich, um sicherzustellen, dass Visual Studio die PyBind11-Bibliotheken finden und Dateien enthalten kann. Weitere Informationen zum Code in diesem Abschnitt finden Sie in den Grundlagen von PyBind11.
Installieren von PyBind11
Der erste Schritt besteht darin, PyBind11 in Ihrer Projektkonfiguration zu installieren. In dieser Übung verwenden Sie das PowerShell-Entwicklerfenster .
Öffnen Sie das Fenster Tools>Command Line>Developer PowerShell.
Installieren Sie pyBind11 im PowerShell-Entwicklerfenster mithilfe des Pip-Befehls
pip install pybind11
oderpy -m pip install pybind11
.Visual Studio installiert PyBind11 und dessen abhängige Pakete.
Hinzufügen von PyBind11-Pfaden zum Projekt
Nach der Installation von PyBind11 müssen Sie die PyBind11-Pfade zur Eigenschaft "Zusätzliche Include-Verzeichnisse" für das Projekt hinzufügen.
Führen Sie im Developer PowerShell-Fenster den Befehl
python -m pybind11 --includes
oderpy -m pybind11 --includes
aus.Diese Aktion druckt eine Liste der PyBind11-Pfade, die Sie zu Ihren Projekteigenschaften hinzufügen müssen.
Markieren Sie die Liste der Pfade im Fenster, und wählen Sie "Kopieren " (Doppelseite) auf der Fenstersymbolleiste aus.
Die Liste der verketteten Pfade wird in deine Zwischenablage kopiert.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt "Superfastcode2 ", und wählen Sie "Eigenschaften" aus.
Wählen Sie oben im Dialogfeld "Eigenschaftenseiten " für das Feld "Konfiguration " die Option "Freigeben" aus. (Möglicherweise wird diese Option mit dem Präfix "Aktiv " angezeigt.)
Erweitern Sie im Dialogfeld auf der Registerkarte "C/C++>Allgemein " das Dropdownmenü für die Eigenschaft "Zusätzliche Includeverzeichnisse ", und wählen Sie "Bearbeiten" aus.
Fügen Sie im Popupdialogfeld die Liste der kopierten Pfade hinzu:
Wiederholen Sie diese Schritte für jeden Pfad in der zusammengesetzten Liste, die aus dem Developer PowerShell-Fenster kopiert wurde.
Wählen Sie im Popup-Dialogfeld auf der Symbolleiste den Eintrag Neue Zeile (Ordner mit Pluszeichen) aus.
Visual Studio fügt oben in der Liste der Pfade eine leere Zeile hinzu und positioniert den Einfügecursor am Anfang.
Fügen Sie den PyBind11-Pfad in die leere Zeile ein.
Sie können auch weitere Optionen (...) auswählen und ein Popup-Datei-Explorer-Dialogfeld verwenden, um zum Pfadspeicherort zu navigieren.
Von Bedeutung
- Wenn der Pfad das
-I
Präfix enthält, entfernen Sie das Präfix aus dem Pfad. - Damit Visual Studio einen Pfad erkennt, muss sich der Pfad in einer separaten Zeile befinden.
Nachdem Sie einen neuen Pfad hinzugefügt haben, zeigt Visual Studio den bestätigten Pfad im Feld "Ausgewerteter Wert " an.
- Wenn der Pfad das
Wählen Sie "OK " aus, um das Popupdialogfeld zu beenden.
Oben im Dialogfeld Eigenschaftenseiten den Mauszeiger über den Wert der Eigenschaft Zusätzliche Includeverzeichnisse halten und bestätigen, dass die PyBind11-Pfade vorhanden sind.
Wählen Sie OK aus, um die Eigenschaftsänderungen zu übernehmen.
Aktualisieren der module.cpp-Datei
Der letzte Schritt besteht darin, der C++-Projektdatei die Headerdatei "PyBind11" und den Makrocode hinzuzufügen.
Öffnen Sie für das Projekt superfastcode2 C++ die module.cpp Datei im Code-Editor.
Fügen Sie oben in der datei module.cpp eine Anweisung hinzu, um die Headerdatei pybind11.h einzuschließen:
#include <pybind11/pybind11.h>
Fügen Sie am Ende der datei module.cpp Code für das
PYBIND11_MODULE
Makro hinzu, um den Einstiegspunkt zur C++-Funktion zu definieren:namespace py = pybind11; PYBIND11_MODULE(superfastcode2, m) { m.def("fast_tanh2", &tanh_impl, R"pbdoc( Compute a hyperbolic tangent of a single argument expressed in radians. )pbdoc"); #ifdef VERSION_INFO m.attr("__version__") = VERSION_INFO; #else m.attr("__version__") = "dev"; #endif }
Erstellen Sie das C++-Projekt, und überprüfen Sie Den Code. Wenn Fehler auftreten, lesen Sie den nächsten Abschnitt, Problembehandlung bei Kompilierungsfehlern.
Beheben von Kompilierungsfehlern
Überprüfen Sie die folgenden Abschnitte auf mögliche Probleme, die dazu führen können, dass der C++-Modulbuild fehlschlägt.
Fehler: Die Headerdatei kann nicht gefunden werden.
Visual Studio gibt eine Fehlermeldung zurück wie E1696: Die Quelldatei "Python.h" kann nicht geöffnet werden oder C1083: Kann die Include-Datei nicht öffnen: "Python.h": Keine solche Datei oder Verzeichnis.
Dieser Fehler gibt an, dass der Compiler keine erforderliche Headerdatei (H) für Ihr Projekt finden kann.
Stellen Sie für das Superfastcode-Projekt sicher, dass die Projekteigenschaft C/C++>General>Zusätzliche Include-Verzeichnisse den Pfad zum Include-Ordner für Ihre Python-Installation enthält. Überprüfen Sie die Schritte in "Projekteigenschaften konfigurieren".
Stellen Sie für das Superfastcode2-Projekt sicher, dass die gleiche Projekteigenschaft den Pfad zum Includeordner für Ihre PyBind11-Installation enthält. Überprüfen Sie die Schritte Ad PyBind-Pfade zum Projekt hinzufügen.
Weitere Informationen zum Zugriff auf Ihre Python-Installationskonfigurationsinformationen finden Sie in der Python-Dokumentation.
Fehler: Python-Bibliotheken können nicht gefunden werden
Visual Studio gibt einen Fehler zurück, der angibt, dass der Compiler die erforderlichen Bibliotheksdateien (DLL) für Ihr Projekt nicht finden kann.
- Stellen Sie für das C++-Projekt (Superfastcode oder Superfastcode2) sicher, dass die Eigenschaft "Zusätzliche>Bibliotheksverzeichnisse> den Pfad zum Ordner "libs" für Ihre Python-Installation enthält. Überprüfen Sie die Schritte in "Projekteigenschaften konfigurieren".
Weitere Informationen zum Zugriff auf Ihre Python-Installationskonfigurationsinformationen finden Sie in der Python-Dokumentation.
Verknüpfungsfehler im Zusammenhang mit der Zielarchitektur
Visual Studio meldet Linkerfehler im Zusammenhang mit der Zielarchitekturkonfiguration für Ihr Projekt, z. B. x64 oder Win32.
- Ändern Sie für das C++-Projekt (Superfastcode oder Superfastcode2) die Zielkonfiguration entsprechend Ihrer Python-Installation. Wenn ihre C++-Projektzielkonfiguration beispielsweise Win32 ist, ihre Python-Installation jedoch 64-Bit ist, ändern Sie die C++-Projektzielkonfiguration in x64.
Testen des Codes und Vergleichen der Ergebnisse
Nachdem Sie nun die DLLs als Python-Erweiterungen strukturiert haben, können Sie von dem Python-Projekt aus darauf verweisen, die Module importieren und ihre Methoden verwenden.
Machen Sie Ihre DLL für Python verfügbar
Sie können Ihre DLL auf verschiedene Arten für Python verfügbar machen. Hier sind zwei Optionen zu berücksichtigen:
Wenn sich Ihr Python-Projekt und das C++-Projekt in derselben Lösung befinden, können Sie den folgenden Ansatz verwenden:
Klicken Sie im Lösungsexplorer mit der rechten Maustaste auf den Knoten Verweise in Ihrem Python-Projekt und wählen Verweis hinzufügen aus.
Achten Sie darauf, diese Aktion für Ihr Python-Projekt und nicht für Ihr C++-Projekt auszuführen.
Erweitern Sie im Dialogfeld " Verweis hinzufügen " die Registerkarte "Projekte ".
Aktivieren Sie die Kontrollkästchen für die Projekte "Superfastcode2 " und " Superfastcode2 ", und wählen Sie "OK" aus.
Ein alternativer Ansatz besteht darin, das C++-Erweiterungsmodul in Ihrer Python-Umgebung zu installieren. Diese Methode stellt das Modul anderen Python-Projekten zur Verfügung. Weitere Informationen finden Sie in der Setuptools-Projektdokumentation.
Führen Sie die folgenden Schritte aus, um das C++-Erweiterungsmodul in Ihrer Python-Umgebung zu installieren:
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Ihr C++-Projekt, und wählen Sie"Neues Element> aus.
Wählen Sie in der Liste der Dateivorlagen C++-Datei (.cpp) aus.
Geben Sie den Namen für die Datei als setup.py ein, und wählen Sie dann "Hinzufügen" aus.
Achten Sie darauf, den Dateinamen mit der Erweiterung Python (.py) einzugeben. Visual Studio erkennt die Datei trotz der Verwendung der C++-Dateivorlage als Python-Code.
Visual Studio öffnet die neue Datei im Code-Editor.
Fügen Sie den folgenden Code in die neue Datei ein. Wählen Sie die Codeversion aus, die Ihrer Erweiterungsmethode entspricht:
CPython-Erweiterungen (Superfastcode-Projekt ):
from setuptools import setup, Extension sfc_module = Extension('superfastcode', sources = ['module.cpp']) setup( name='superfastcode', version='1.0', description='Python Package with superfastcode C++ extension', ext_modules=[sfc_module] )
PyBind11 (Superfastcode2-Projekt ):
from setuptools import setup, Extension import pybind11 cpp_args = ['-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.7'] sfc_module = Extension( 'superfastcode2', sources=['module.cpp'], include_dirs=[pybind11.get_include()], language='c++', extra_compile_args=cpp_args, ) setup( name='superfastcode2', version='1.0', description='Python package with superfastcode2 C++ extension (PyBind11)', ext_modules=[sfc_module], )
Erstellen Sie im C++-Projekt eine zweite Datei mit dem Namen pyproject.toml, und fügen Sie den folgenden Code ein:
[build-system] requires = ["setuptools", "wheel", "pybind11"] build-backend = "setuptools.build_meta"
Die TOML (.toml)-Datei verwendet das Format "Tom's Obvious, Minimal Language" für Konfigurationsdateien.
Um die Erweiterung zu erstellen, klicken Sie mit der rechten Maustaste auf den Dateinamen pyproject.toml auf der Registerkarte "Codefenster", und wählen Sie "Vollständigen Pfad kopieren" aus.
Sie löschen den Pyproject.toml-Namen aus dem Pfad, bevor Sie ihn verwenden.
Erweitern Sie im Projektmappen-Explorer den Knoten Python-Umgebungen für die Lösung.
Klicken Sie mit der rechten Maustaste auf die aktive Python-Umgebung (fett dargestellt), und wählen Sie "Python-Pakete verwalten" aus.
Der Bereich "Python-Umgebungen " wird geöffnet.
Wenn das erforderliche Paket bereits installiert ist, wird es in diesem Bereich aufgeführt.
- Bevor Sie fortfahren, wählen Sie das X neben dem Paketnamen aus, um es zu deinstallieren.
Fügen Sie im Suchfeld für den Bereich "Python-Umgebungen " den kopierten Pfad ein, und löschen Sie den Dateinamen "pyproject.toml " am Ende des Pfads.
Wählen Sie die EINGABETASTE, um das Modul vom Speicherort des kopierten Pfads zu installieren.
Tipp
Wenn die Installation aufgrund eines Berechtigungsfehlers fehlschlägt, fügen Sie das
--user
Argument am Ende des Befehls hinzu, und versuchen Sie es erneut.
Aufrufen der DLL aus Python
Nachdem Sie die DLL für Python verfügbar machen, wie im vorherigen Abschnitt beschrieben, können Sie die superfastcode.fast_tanh
Funktionen und superfastcode2.fast_tanh2
Funktionen von Python aufrufen. Anschließend können Sie die Funktionsleistung mit der Python-Implementierung vergleichen.
Führen Sie die folgenden Schritte aus, um die Erweiterungsmodul-DLL aus Python aufzurufen:
Öffnen Sie die .py Datei für Ihr Python-Projekt im Code-Editor.
Fügen Sie am Ende der Datei den folgenden Code hinzu, um die aus den DLLs exportierten Methoden aufzurufen und deren Ausgabe anzuzeigen:
from superfastcode import fast_tanh test(lambda d: [fast_tanh(x) for x in d], '[fast_tanh(x) for x in d] (CPython C++ extension)') from superfastcode2 import fast_tanh2 test(lambda d: [fast_tanh2(x) for x in d], '[fast_tanh2(x) for x in d] (PyBind11 C++ extension)')
Führen Sie das Python-Programm aus, indem Sie " Debuggen>starten ohne Debuggen " auswählen oder die Tastenkombination STRG+F5 verwenden.
Hinweis
Wenn der Befehl "Ohne Debuggen starten " nicht verfügbar ist, klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Python-Projekt, und wählen Sie dann "Als Startprojekt festlegen" aus.
Beachten Sie beim Ausführen des Programms, dass die C++-Routinen ungefähr 5 bis 20 Mal schneller ausgeführt werden als die Python-Implementierung.
Hier ist ein Beispiel für die typische Programmausgabe:
Running benchmarks with COUNT = 500000 [tanh(x) for x in d] (Python implementation) took 0.758 seconds [fast_tanh(x) for x in d] (CPython C++ extension) took 0.076 seconds [fast_tanh2(x) for x in d] (PyBind11 C++ extension) took 0.204 seconds
Versuchen Sie, die
COUNT
Variable zu erhöhen, sodass die Zeitunterschiede ausgeprägter sind.Ein Debugbuild des C++-Moduls wird auch langsamer als ein Releasebuild ausgeführt, da der Debugbuild weniger optimiert ist und verschiedene Fehlerprüfungen enthält. Versuchen Sie, zwischen den Buildkonfigurationen für den Vergleich zu wechseln, denken Sie jedoch daran, die Eigenschaften zu aktualisieren, die Sie zuvor für die Releasekonfiguration festgelegt haben.
Adressierung von Prozessgeschwindigkeit und Aufwand
In der Ausgabe stellen Sie möglicherweise fest, dass die PyBind11-Erweiterung nicht so schnell ist wie die CPython-Erweiterung, obwohl sie schneller sein sollte als die reine Python-Implementierung. Der Hauptgrund für den Unterschied ist die Verwendung der METH_O Kennzeichnung. Dieses Flag unterstützt nicht mehrere Parameter, Parameternamen oder Schlüsselwörterargumente. PyBind11 generiert etwas komplexeren Code, um eine pythonähnliche Schnittstelle für Aufrufer bereitzustellen. Da der Testcode die Funktion 500.000 Mal aufruft, können die Ergebnisse den Aufwand erheblich verstärken.
Sie können den Aufwand weiter reduzieren, indem Sie die for
Schleife in den systemeigenen Python-Code verschieben. Dieser Ansatz umfasst die Verwendung des Iteratorprotokolls (oder des PyBind11-Typs py::iterable
für den Funktionsparameter), um jedes Element zu verarbeiten. Das Entfernen der wiederholten Übergänge zwischen Python und C++ ist eine effektive Möglichkeit, die Zeit zu reduzieren, die zum Verarbeiten der Sequenz benötigt wird.
Problembehandlung bei Importfehlern
Wenn Sie eine ImportError
Nachricht erhalten, wenn Sie versuchen, Ihr Modul zu importieren, können Sie sie auf eine der folgenden Arten auflösen:
Wenn Sie durch einen Projektverweis kompilieren, stellen Sie sicher, dass die Eigenschaften Ihres C++-Projekts mit der aktivierten Python-Umgebung für Ihr Python-Projekt übereinstimmen. Vergewissern Sie sich, dass die gleichen Ordnerspeicherorte für die Dateien Include (.h) und Library (DLL) verwendet werden.
Stellen Sie sicher, dass Die Ausgabedatei richtig benannt ist, z. B. superfastcode.pyd. Ein falscher Name oder eine falsche Erweiterung verhindert den Import der erforderlichen Datei.
Wenn Sie Ihr Modul mithilfe der setup.py-Datei installieren, müssen Sie den
pip
Befehl in der Python-Umgebung ausführen, die für Ihr Python-Projekt aktiviert ist. Wenn Sie die aktive Python-Umgebung für Ihr Projekt im Projektmappen-Explorer erweitern, sollte ein Eintrag für das C++-Projekt angezeigt werden, z. B. Superfastcode.
Debuggen von C++-Code
Visual Studio unterstützt das Gemeinsame Debuggen von Python- und C++-Code. Die folgenden Schritte veranschaulichen den Debugprozess für das Superfastcode-C ++-Projekt, aber der Prozess ist für das Superfastcode2-Projekt identisch.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Python-Projekt, und wählen Sie "Eigenschaften" aus.
Wählen Sie im Eigenschaftenbereich die Registerkarte " Debuggen " und dann die Option "Systemeigenes>Debuggen aktivieren" aus .
Tipp
Wenn Sie das Debugging des nativen Codes aktivieren, wird das Python-Ausgabefenster möglicherweise sofort geschlossen, nachdem das Programm beendet wurde, ohne anzuhalten und den Hinweis Press any key to continue anzuzeigen. Um die Pause und Eingabeaufforderung zu erzwingen, nachdem Sie das native Code-Debugging aktiviert haben, fügen Sie das
-i
Argument zum Feld "Ausführen>-Interpreterargumente" auf der Registerkarte "Debuggen" hinzu. Dieses Argument versetzt den Python-Interpreter nach Ausführung des Codes in den interaktiven Modus. Das Programm wartet, bis Sie STRG+Z+EINGABETASTE zum Schließen des Fensters gedrückt haben. Ein alternativer Ansatz besteht darin, am Ende Ihres Python-Programmsimport os
- undos.system("pause")
-Anweisungen hinzuzufügen. Dieser Code dupliziert die ursprüngliche Pausenaufforderung.Wählen Sie "Datei>speichern " (oder STRG+S) aus, um die Eigenschaftsänderungen zu speichern.
Legen Sie auf der Visual Studio-Symbolleiste die Buildkonfiguration auf "Debuggen" fest.
Da die Ausführung des Codes im Debugger in der Regel länger dauert, können Sie die
COUNT
Variable in Ihrem Python-Projekt .py Datei in einen Wert ändern, der ungefähr fünfmal kleiner als der Standardwert ist. Ändern Sie sie beispielsweise von 500000 in 100000.Legen Sie in Ihrem C++-Code einen Haltepunkt in der ersten Zeile der
tanh_impl
Methode fest.Starten Sie den Debugger, indem Sie "Debuggen>starten" auswählen oder die Tastenkombination F5 verwenden.
Der Debugger hält an, wenn der Haltepunktcode aufgerufen wird. Wenn der Haltepunkt nicht erreicht ist, überprüfen Sie, ob die Konfiguration auf "Debuggen" festgelegt ist und dass Sie das Projekt gespeichert haben, was beim Starten des Debuggers nicht automatisch erfolgt.
Am Haltepunkt können Sie den C++-Code durchlaufen, Variablen untersuchen usw. Weitere Informationen zu diesen Features finden Sie unter "Debuggen von Python und C++" zusammen.
Alternative Ansätze
Sie können Python-Erweiterungen auf verschiedene Arten erstellen, wie in der folgenden Tabelle beschrieben. Die ersten beiden Zeilen, CPython
und PyBind11
, werden in diesem Artikel erläutert.
Vorgehensweise | Jahrgang | Repräsentative Benutzer |
---|---|---|
C/C++-Erweiterungsmodule für CPython |
1991 | Standardbibliothek |
PyBind11 (empfohlen für C++) | 2015 | |
Cython (empfohlen für C) | 2007 | gevent, kivy |
HPy | 2019 | |
mypyc | 2017 | |
ctypes | 2003 | oscrypto |
cffi | 2013 | Kryptografie, Pypy |
SAUFEN | 1996 | crfsuite |
Boost.Python | 2002 | |
cppyy | 2017 |