Freigeben über


Erstellen einer C++-Erweiterung für Python in Visual Studio

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.

    Screenshot einer Liste der Python-Entwicklungsoptionen, die die Option

    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.

  1. Erstellen Sie ein neues Python-Projekt in Visual Studio, indem Sie Datei>Neu>Projekt auswählen.

  2. Suchen Sie im Dialogfeld " Neues Projekt erstellen " nach Python. Wählen Sie die Python-Anwendungsvorlage und dann "Weiter" aus.

  3. 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.

  4. 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)')
    
  5. 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.

  6. 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.

  7. 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.

  8. 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.

  1. 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.

  2. Legen Sie im Dialogfeld "Neues Projekt hinzufügen" den Sprachfilter auf C++ fest, und geben Sie im Suchfeldleer ein.

  3. Wählen Sie in der Liste der Projektvorlagenergebnisse " Leeres Projekt" und dann "Weiter" aus.

  4. 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.
  5. 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.

  1. Erweitern Sie im Projektmappen-Explorer das Projekt, klicken Sie mit der rechten Maustaste auf den Knoten "Quelldateien", und wählen Sie "Neues Element> aus.

  2. Wählen Sie in der Liste der Dateivorlagen C++-Datei (.cpp) aus.

  3. 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.

  4. Erweitern Sie auf der Symbolleiste das Dropdownmenü " Konfiguration ", und wählen Sie ihren Zielkonfigurationstyp aus:

    Screenshot, der zeigt, wie der Zielkonfigurationstyp für das C++-Projekt in Visual Studio festgelegt wird.

    • 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.

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das C++-Modulprojekt (Superfastcode oder Superfastcode2), und wählen Sie "Eigenschaften" aus.

  2. 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:

    Screenshot, der zeigt, wie Sie die Projektbuild- und Plattformoptionen für die C++-Datei in Visual Studio festlegen.

    1. Wählen Sie für die Konfiguration"Debuggen " oder "Freigeben" aus. (Möglicherweise werden diese Optionen mit dem Präfix "Aktiv " angezeigt.)

    2. 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.

    3. 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 Sie python_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.

    4. Nachdem Sie alle Eigenschaften aktualisiert haben, wählen Sie "OK" aus.

    Wiederholen Sie die Schritte für die andere Buildkonfiguration.

  3. Testen Sie Ihre aktuelle Konfiguration. Wiederholen Sie die folgenden Schritte für die Debug- und Release-Builds beider C++-Projekte.

    1. Legen Sie auf der Visual Studio-Symbolleiste die Buildkonfiguration auf "Debuggen " oder "Release" fest:

      Screenshot, der zeigt, wie die Buildkonfiguration für das C++-Projekt in Visual Studio festgelegt wird.

    2. 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.

  1. Öffnen Sie für das Superfastcode-C ++-Projekt die module.cpp Datei im Code-Editor.

  2. 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);
    }
    
  3. Speichern Sie Ihre Änderungen.

  4. 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.

  1. Öffnen Sie für das Superfastcode-C ++-Projekt die module.cpp Datei im Code-Editor.

  2. Fügen Sie oben in der datei module.cpp eine Anweisung hinzu, um die Python.h-Headerdatei einzuschließen:

    #include <Python.h>
    
  3. Ersetzen Sie den tanh_impl Methodencode, um Python-Typen zu akzeptieren und zurückzugeben (d. r.: a PyObject*):

    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);
    }
    
  4. 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 }
    };
    
  5. 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 die from superfastcode import fast_tanh Anweisung in Python verwenden können, da fast_tanh sie innerhalb superfastcode_methodsdefiniert 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
    };
    
  6. Fügen Sie eine Methode hinzu, die Python aufruft, wenn das Modul geladen wird. Der Methodenname muss seinPyInit_<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);
    }
    
  7. 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 .

  1. Öffnen Sie das Fenster Tools>Command Line>Developer PowerShell.

  2. Installieren Sie pyBind11 im PowerShell-Entwicklerfenster mithilfe des Pip-Befehls pip install pybind11 oder py -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.

  1. Führen Sie im Developer PowerShell-Fenster den Befehl python -m pybind11 --includes oder py -m pybind11 --includes aus.

    Diese Aktion druckt eine Liste der PyBind11-Pfade, die Sie zu Ihren Projekteigenschaften hinzufügen müssen.

  2. Markieren Sie die Liste der Pfade im Fenster, und wählen Sie "Kopieren " (Doppelseite) auf der Fenstersymbolleiste aus.

    Screenshot, der zeigt, wie Sie die Liste der Pfade aus dem PowerShell-Entwicklerfenster in Visual Studio hervorheben und kopieren.

    Die Liste der verketteten Pfade wird in deine Zwischenablage kopiert.

  3. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt "Superfastcode2 ", und wählen Sie "Eigenschaften" aus.

  4. 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.)

  5. 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.

  6. 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.

    1. Wählen Sie im Popup-Dialogfeld auf der Symbolleiste den Eintrag Neue Zeile (Ordner mit Pluszeichen) aus.

      Screenshot, der zeigt, wie Sie der Eigenschaft Additional Include Directories einen PyBind11-Pfad hinzufügen.

      Visual Studio fügt oben in der Liste der Pfade eine leere Zeile hinzu und positioniert den Einfügecursor am Anfang.

    2. 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.

  7. Wählen Sie "OK " aus, um das Popupdialogfeld zu beenden.

  8. Oben im Dialogfeld Eigenschaftenseiten den Mauszeiger über den Wert der Eigenschaft Zusätzliche Includeverzeichnisse halten und bestätigen, dass die PyBind11-Pfade vorhanden sind.

  9. 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.

  1. Öffnen Sie für das Projekt superfastcode2 C++ die module.cpp Datei im Code-Editor.

  2. Fügen Sie oben in der datei module.cpp eine Anweisung hinzu, um die Headerdatei pybind11.h einzuschließen:

    #include <pybind11/pybind11.h>
    
  3. 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
    }
    
  4. 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.

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:

  1. 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.

  2. Erweitern Sie im Dialogfeld " Verweis hinzufügen " die Registerkarte "Projekte ".

  3. Aktivieren Sie die Kontrollkästchen für die Projekte "Superfastcode2 " und " Superfastcode2 ", und wählen Sie "OK" aus.

    Screenshot, der zeigt, wie Sie einen Verweis auf das super schnelle Codeprojekt in Visual Studio hinzufügen.

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:

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Ihr C++-Projekt, und wählen Sie"Neues Element> aus.

  2. Wählen Sie in der Liste der Dateivorlagen C++-Datei (.cpp) aus.

  3. 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.

  4. 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],
      )
      
  5. 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.

  6. 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.

    Screenshot, der zeigt, wie Der vollständige Pfad zur Toml-Datei des Py-Projekts in Visual Studio kopiert wird.

    Sie löschen den Pyproject.toml-Namen aus dem Pfad, bevor Sie ihn verwenden.

  7. Erweitern Sie im Projektmappen-Explorer den Knoten Python-Umgebungen für die Lösung.

  8. 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.

    Screenshot, der zeigt, wie Sie ein Paket im Bereich

  9. 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.

    Screenshot, der zeigt, wie Sie den Pfad im Bereich

  10. 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:

  1. Öffnen Sie die .py Datei für Ihr Python-Projekt im Code-Editor.

  2. 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)')
    
  3. 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
    
  4. 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.

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Python-Projekt, und wählen Sie "Eigenschaften" aus.

  2. 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-Programms import os- und os.system("pause")-Anweisungen hinzuzufügen. Dieser Code dupliziert die ursprüngliche Pausenaufforderung.

  3. Wählen Sie "Datei>speichern " (oder STRG+S) aus, um die Eigenschaftsänderungen zu speichern.

  4. Legen Sie auf der Visual Studio-Symbolleiste die Buildkonfiguration auf "Debuggen" fest.

  5. 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.

  6. Legen Sie in Ihrem C++-Code einen Haltepunkt in der ersten Zeile der tanh_impl Methode fest.

  7. 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.

    Screenshot von C++-Code, der einen Haltepunkt in Visual Studio enthält.

  8. 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