在 Visual Studio 中建立 Python 的 C++ 擴充

在本文中,我們為 CPython 建構一個 C++ 擴充模組,用來計算雙曲正切,並從 Python 程式碼中呼叫它。 常式先以 Python 實作,以示範用 C++ 實作相同常式時的相對效能改善。

以 C++ (或C) 編寫的程式碼模組通常用於擴充 Python 解譯器的功能。 擴充模組主要有三種型別:

  • 加速模組:啟用加速效能。 因為 Python 是一種解譯語言,所以您可以用 C++ 編寫加速器模組以獲得更高的效能。
  • 包裝程式模組:將現有的 C/C++ 介面公開給 Python 程式碼,或公開更類似 Python 的 API,從 Python 很容易使用。
  • 低階系統存取模組:建立系統存取模組,以達到CPython執行階段、作業系統或底層硬體的低階功能。

本文展示使 C++ 擴充模組可用於 Python 的兩種方法:

  • 使用標準 CPython 延伸模組,如 Python 文件中所述。
  • 使用 PyBind11,建議針對 C++ 11 使用,因為其簡單性。 為確保相容性,請確定您使用的是較新的 Python 版本。

此演練的完整範例可在 GitHub 上取得,網址為 Python-samples-vs-cpp-extension。

必要條件

  • 安裝 Python 開發工作負載的 Visual Studio 2017 或更新版本。 工作負荷包括 Python 原生開發工具,它增加原生擴充所需的 C++ 工作負荷和工具集。

    Screenshot of a list of Python development options, highlighting the Python native development tools option.

    如需安裝選項的詳細資訊,請參閱安裝適用於 Visual Studio 的 Python 支援

    注意

    安裝 [資料科學和分析應用程式] 工作負載時,預設會安裝 Python 和 [Python 原生開發工具] 選項。

  • 如果您單獨安裝 Python ,請務必在 Python 安裝程式的 Advanced Options 下選取 Download debugging symbols。 需要此選項,您才能在 Python 程式碼與機器碼之間使用混合模式偵錯。

建立 Python 應用程式

按照以下步驟來建立 Python 應用程式。

  1. 在 Visual Studio 中建立新的 Python 專案,方法是選取 [檔案]>[新增]>[專案]

  2. Create a new project 對話方塊中,搜尋 Python。 選取 Python Application,然後選取 Next。

  3. 輸入Project name 和 Location 然後選取 Create。

    Visual Studio 會建立新專案。 專案在 Solution Explorer 中開啟,專案檔案 (.py) 在程式碼編輯器中開啟。

  4. .py,貼上下列程式碼。 若要體驗某些 Python 編輯功能,請嘗試手動輸入程式碼。

    這個程式碼不使用數學程式庫來計算雙曲正切,而這就是您稍後使用 Python 原生延伸所加速的方式。

    提示

    請先以單純 Python 撰寫程式碼,之後再於 C++ 中重寫程式碼。 這樣,您就可以更輕鬆地檢查以確保您的原生 Python 程式碼是正確的。

    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. 選取Debug >Start without Debugging,或選取鍵盤捷徑 Ctrl+F5, 即可執行程式。

    命令視窗會開啟,以顯示程式輸出。

  6. 在輸出中,請注意為基準程式報告的時間量。

    本演練的基準測試程式大約需要 2 秒時間。

  7. 根據需要,調整程式碼中的變COUNT量值,使基準測試能夠在電腦上大約 2 秒內完成。

  8. 再次執行程式,並確認修改後的COUNT值會在 2 秒內產生效能基準。

提示

當您執行效能指標時,請一律使用Debug >Start without Debugging 選項。 此方法有助於避免在 Visual Studio 偵錯工具中執行程式碼時產生的額外負荷。

建立核心 C++ 專案

請依照下列步驟建立兩個相同的 C++ 專案:superfastcode 和 superfastcode2。 稍後,在每個專案中使用不同的方法將 C++ 程式碼公開給 Python。

  1. Solution Explorer,用滑鼠右鍵按一下方案名稱,>然後選取 Add New Project。

    Visual Studio 解決方案可以同時包含 Python 和 C++ 專案,這是使用 Visual Studio for Python 開發的優勢之一。

  2. Add a new project 對話方塊中,將 Language 篩選條件設定為 C++, 然後在Search 方塊中輸入空白。

  3. 在專案範本結果清單中,選取 Empty project,然後選取 Next。

  4. Configure your new project 對話方塊中,輸入 Project name:

    • 對於第一個專案,輸入名稱 superfastcode。
    • 對於第二個專案,請輸入名稱 superfastcode2。
  5. 選取 建立

請務必重複這些步驟並建立兩個專案。

提示

當您在 Visual Studio 中安裝 Python 原生開發工具時,可以使用另一種方法。 您可以從 Python Extension Module 範本開始,它預先完成本文中介紹的許多步驟。

對於本文的逐步說明,從空專案開始有助於演示如何逐步構建擴充模組。 瞭解此程式後,您可以使用替代範本來節省編寫自己的副檔名時的時間。

將 C++ 檔案加入專案

接著,在每個專案中加入 C++ 檔案。

  1. Solution Explorer,展開專案,在 Source Files 節點上按一下>滑鼠右鍵,然後選取 Add New Item。

  2. 在檔案範本清單中,選取 C++ 檔案 (.cpp)。

  3. 以 module.cpp,輸入檔案的 Name,然後選取 Add。

    重要

    請確定檔案名稱包含 .cpp 副檔名。 Visual Studio 會尋找副檔名為 .cpp,以啟用 C++ 專案屬性頁的顯示。

  4. 在工具列上,展開 Configuration 下拉式功能表,然後選取您的目標組態型別:

    Screenshot that shows how to set the target configuration type for the C++ project in Visual Studio.

    • 針對 64 位元 Python 執行階段,請啟動 x64 設定。
    • 針對 32 位元 Python 執行階段,請啟動 Win32 設定。

請務必為兩個專案重複這些步驟。

設定專案屬性

將程式碼新增到新的 C++ 檔案之前,請配置每個 C++ 模組專案的屬性,並測試配置以確保一切都正常工作。

您需要為每個模組的偵錯釋出建構組態設定專案屬性。

  1. Solution Explorer,以滑鼠右鍵按一下 C++ 模組專案 (superfastcode superfastcode2),然後選取Properties。

  2. 設定模組偵錯建置的屬性,然後設定發行建置的相同屬性:

    在專案 Property Pages 對話方塊的頂端,設定下列檔案組態選項:

    Screenshot that shows how to set the project build and platform options for the C++ file in Visual Studio.

    1. Configuration,選取 Debug Release。 (您可能會看到這些選項帶有 Active 前綴詞。)

    2. 若為 Platform,請根據您在前一步驟中所做的選擇,選取 Active (x64) 或 Active (Win32)。

      注意

      當您建立自己的專案時,您要根據您的特定案例需求,分別設定偵錯釋出組態。 在本練習中,您將配置設定為使用 CPython 的發行版本。 此設定會停用 C++ 執行階段的一些偵錯功能,包括判斷提示。 使用 CPython 偵錯二進位檔 (python_d.exe) 需要不同的設定。

    3. 如下表所述,設定其他專案屬性。

      若要變更屬性值,請在屬性欄位中輸入值。 對於某些欄位,您可以選取目前的值以展開下拉式選單,或開啟對話方塊以協助定義值。

      更新標籤上的值後,請選取套用,然後再切換至其他標籤。此動作有助於確保您的變更保留下來。

      索引標籤與區段 屬性
      組態屬性>一般 目標名稱 指定從 Python 在語from...import句 (例如superfastcode) 中參考的模組名稱。 當您定義 Python 的模組時,會在 C++ 程式碼中使用此相同名稱。 若要使用專案的名稱當作模組名稱,請保留預設值 $<ProjectName>。 針對 python_d.exe,將 _d 新增至名稱的結尾。
      組態類型 動態程式庫 (.dll)
      組態屬性>進階 目標副檔名 .pyd (Python 擴充模組)
      C/C++>一般 其他 Include 目錄 視安裝情況新增 Python include 資料夾 (例如 c:\ Python 36\include)。
      C/C++>前置處理器 前置處理器定義 如果存在,請將 _DEBUG 值變更為 NDEBUG,以符合 CPython 的非偵錯版本。 使用 Python _d.exe,請保持此值不變。
      C/C++>程式碼產生 執行階段程式庫 多重執行緒 DLL(/MD),以符合 CPython 的發行 (非偵錯) 版本。 使用 python_d.exe ,請將此值保留為 Multi-threaded Debug DLL (/MDd)。
      基本執行階段檢查 Default
      連結器>一般 其他程式庫目錄 視您的安裝情況新增包含 .lib 檔案的 Python libs 資料夾 (例如 c:\Python36\libs)。 請務必指向包含 .lib 檔案的 libs 資料夾,而不是包含 .py 檔案的 Lib 資料夾。

      重要

      如果 C/C++ 標籤未顯示為專案屬性的選項,則專案不會包含 Visual Studio 識別為 C/ C++ 原始檔的程式碼檔案。 如果您建立來源檔案,而沒有 .c.cpp 副檔名,便可能發生此情形。

      如果在建立 C++ 檔案時意外輸入 module.coo,而非module.cpp,則 Visual Studio 將建立該檔案,但不會將檔案型別設定為 C/C+ 編譯器。 此檔案型別是啟動專案屬性對話方塊中 C/C++ 屬性標籤存在的必要型別。 即使您以 .cpp 副檔名重新命名程式碼檔,仍會保留錯誤識別。

      若要正確設定程式碼檔案型別,請在 Solution Explorer,以滑鼠右鍵按一下程式碼檔案,然後選取 Properties。 對於 Item Type,選擇 C/ C++ 編譯器。

    4. 更新所有屬性後,選取 OK。

    對其他組建組態重複這些步驟。

  3. 測試您目前的組態。 對兩個 C++ 專案的 偵錯釋出建置重複下列步驟。

    1. 在 Visual Studio 工具列上,將 Build 組態設定Debug 或 Release:

      Screenshot that shows how to set the build configuration for the C++ project in Visual Studio.

    2. Solution Explorer,在 C++ 專案上按一下滑鼠右鍵,然後選取建置。

      .pyd 檔案位於 solution 資料夾下的 Debug 和 Release,而不是 C++ 專案資料夾本身。

新增程式碼與測試組態

現在,您可以向 C++ 檔案新增程式碼並測試版本建置。

  1. 對於 superfastcode C++ 專案,請在程式碼編輯器中開啟 module.cpp。

  2. module.cpp 檔案中,貼上下列程式碼:

    #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. 儲存您的變更。

  4. 建立 C++ 專案的發行組態,以確認您的程式碼是正確的。

重複上述步驟,將程式碼加入 superfastcode2 (C++ 檔案) 並測試發行建置。

將 C++ 專案轉換為 Python 擴充功能

若要讓 C++ DLL 成為 Python 的擴充,請先修改匯出的方法以與 Python 型別互動。 然後,新增一個函式以匯出該模組,以及該模組方法的定義。

以下各節演示如何使用 CPython 擴充和 PyBind11 建立擴充。 superfasctcode 專案使用 CPython 擴充功能,而 superfasctcode2 專案實作 PyBind11。

使用 CPython 延伸模組

有關本節中顯示的程式碼的詳細資訊,請參閱Python/C API 參考手冊,尤其是 Module Objects 頁面。 當您檢閱參考內容時,請務必在右上角的下拉式清單中選取您的 Python 版本。

  1. 對於 superfastcode C++ 專案,請在程式碼編輯器中開啟 module.cpp。

  2. module.cpp 檔案的頂端新增陳述式,以包含 Python.h header 檔案:

    #include <Python.h>
    
  3. 取代方法tanh_impl程式碼以接受並傳回 Python 型別 (亦即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. 在檔案的末尾,新增一個結構來定義如何向 Python 顯示 C++ tanh_impl函式:

    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. 新增另一個結構以定義如何在 Python 程式碼中引用模組,特別是在使用from...import語句時。

    在此程式碼中匯入的名稱應該符合 Configuration >Properties General >Target Name 下專案屬性的值。

    在下列範例中,"superfastcode"名稱表示您可以使用 Python 中的from superfastcode import fast_tanh陳述式,因為fast_tanh是在superfastcode_methods中定義的。 module.cpp 等 C++ 專案的內部檔案名稱不太重要。

    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. 加入 Python 在載入模組時呼叫的方法。 方法名稱必須PyInit_<module-name>是,其中 <module-name,>與 C++ 專案的 Configuration >Properties General >Target Name 屬性完全相符。 也就是說,方法名稱與專案所建置的 .pyd 檔案的檔案名稱相符。

    PyMODINIT_FUNC PyInit_superfastcode() {
        return PyModule_Create(&superfastcode_module);
    }
    
  7. 建立 C++ 專案並驗證您的程式碼。 如果遇到錯誤,請參見 Troubleshoot compile errors 部分。

使用 PyBind11

如果完成 superfastcode 專案上一節中的步驟,您可能注意到練習需要樣板程式碼來建立 C++ C Python 擴充的模組結構。 在本練習中,您探索 PyBind11 簡化編碼過程。 在 C++ 標頭檔案中使用巨集可達成相同的結果,但使用的程式碼要少得多。 但是,需要執行額外的步驟來確保 Visual Studio 能夠找到 PyBind11 程式庫並包含檔案。 如需本節中程式碼的詳細資訊,請參閱 PyBind11 基本概念

安裝 PyBind11

第一步是在專案組態中安裝 PyBind11。 在本練習中,您將使用 Developer PowerShell 視窗。

  1. 開啟 >Tools Command >Line Developer PowerShell 視窗。

  2. Developer PowerShell 視窗中,pip install pybind11使用 pip 指令或py -m pip install pybind11來安裝 PyBind11。

    Visual Studio 會安裝 PyBind11 及其相依套件。

將 PyBind11 路徑加入專案

安裝 PyBind11 之後,您必須將 PyBind11 路徑加入專案的 Additional Include Directories。

  1. Developer PowerShell,視窗中python -m pybind11 --includes執行命py -m pybind11 --includes令或。

    這個動作會列印需要新增至專案屬性的 PyBind11 路徑清單。

  2. 反白視窗中的路徑清單,並在視窗工具列上選取 Copy (雙頁)。

    Screenshot that shows how to highlight and copy the list of paths from the Developer PowerShell window in Visual Studio.

    串連路徑清單會新增至剪貼簿。

  3. Solution Explorer,以滑鼠右鍵按一下 superfastcode2,然後選取 Properties。

  4. Property Pages 對話方塊的頂端,針對 Configuration 欄位選取 Release。 (您可能會看到這個選項有 Active 前綴。)

  5. 在對話方塊中的 C/C++ >General 標籤中,展開 Additional include Directories 屬性的下拉式功能表,然後選取 Copy。

  6. 在彈出式對話方塊中,新增複製的路徑清單:

    針對從 Developer PowerShell 視窗複製的串連清單中的每個路徑,重複下列步驟:

    1. 在彈出式對話方塊工具列上選取 New Line (包含加號符號的資料夾)。

      Screenshot that shows how to add a PyBind11 path to the Additional Include Directories property.

      Visual Studio 會在路徑清單的頂端新增空行,並將插入游標置於開頭。

    2. 將 PyBind11 路徑貼到空行中。

      您也可以選取 More options (...),並使用快顯檔案總管對話方塊瀏覽至路徑位置。

      重要

      • 如果路徑包含前-I綴,請從路徑中移除字首。
      • Visual Studio 若要辨識路徑,路徑必須位於不同的行上。

      新增新路徑後,Visual Studio 會在評估值欄位中顯示確認的路徑。

  7. 選取 OK,結束彈出式對話方塊。

  8. Property Pages 對話方塊的頂端,將游標停留在 Additional indlue Directories 屬性的值上,並確認存在 PyBind11 路徑。

  9. 選取確定,以套用屬性變更。

更新 module.cpp 檔案

最後一步是將 PyBind11 標頭檔案和宏程式碼新增到專案 C++ 檔案中。

  1. 對於 superfastcode2 C++ 專案,請在程式碼編輯器中開啟 module.cpp 檔案。

  2. module.cpp 檔案的頂端加入陳述式,以包含 pybind11.h 標頭檔案:

    #include <pybind11/pybind11.h>
    
  3. module.cpp 檔案的結尾,為PYBIND11_MODULE巨集新增程式碼,以定義 C++ 函式的入口點:

    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. 建立 C++ 專案並驗證您的程式碼。 如果遇到錯誤,請參見下一節,Troubleshoot compile errors。

疑難排解編譯錯誤

請閱讀以下各節,瞭解可能導致 C++ 模組生成失敗的問題。

錯誤:找不到標頭檔

Visual Studio 會傳回錯誤訊息,如 E1696:無法開啟來源檔案 "Python.h",或 C1083:無法開啟包含檔案:"Python.h":沒有這樣的檔案或目錄。

此錯誤表示編譯器找不到專案所需的標頭 (.h ) 檔案。

  • 對於 superfastcode,請確認 C/C++ >General Additional >include Directories 專案屬性包含您 Python 安裝的 include 資料夾的路徑。 檢視Configure project properties。

  • 對於 superfastcode2 專案,請確認相同的專案屬性包含 PyBind11 安裝的 include 資料夾路徑。 檢視將 PyBind 路徑 Ad PyBind paths to project。

有關存取 Python 安裝配置資訊的詳細資訊,請參閱 Python 文件。

錯誤:找不到 Python 程式庫

Visual Studio 傳回錯誤,指出編譯器找不到專案所需的程式庫 (DLL) 檔案。

  • 對於 C++ 專案 (superfastcode superfastcode2),請確認 Linker >General Additional >Library Directories 屬性包含 Python 安裝 libs 資料夾的路徑。 檢視Configure project properties。

有關存取 Python 安裝配置資訊的詳細資訊,請參閱 Python 文件。

Visual Studio 報告與專案的目標架構組態相關的連結器錯誤,例如 x64 或 Win32。

  • 對於 C++ 專案 (superfastcode 或superfastcode2),請變更目標組態以符合您的 Python 安裝。 例如,如果您的 C++ 專案目標組態是 Win32,但您的 Python 安裝是 64 位元,請將 C++ 專案目標組態變更為 x64。

測試程式碼,並比較結果

現在您已將 DLL 結構化成為 Python 延伸模組,您可以從 Python 專案參考它們、匯入模組,並使用其方法。

讓 Python 可以使用您的 DLL

您可以用多種方式將您的 DLL提供給 Python。 以下是兩個可供考慮的選項:

如果您的 Python 專案與 C++ 專案位於相同的解決方案中,您可以使用下列方法:

  1. Solution Explorer,用滑鼠右鍵按一下 Python 專案中的 References,然後選取Add Reference。

    請務必為 Python 專案執行此動作,而不是為 C++ 專案執行此動作。

  2. Add Reference 對話方塊中,展開 Projects 頁籤。

  3. 選取 superfastcode superfastcode2 專案的核取方塊,然後選取 OK。

    Screenshot that shows how to add a reference to the super fast code project in Visual Studio.

另一種方法是在 Python 環境中安裝 C++ 擴充模組。 此方法使此模組可供其他 Python 專案使用。 有關詳細資訊,請參見 setuptools 專案文件。

完成以下步驟,在 Python 環境中安裝 C++ 擴充模組:

  1. Solution Explorer,用滑鼠右鍵按一下您的 >C++ 專案,然後選取 Add New Item。

  2. 在檔案範本清單中,選取 C++ 檔案 (.cpp)。

  3. 以 setup.py 格式輸入檔案的 Name,然後選取 Add。

    請務必以 Python (.py) 副檔名輸入檔案名稱。 Visual Studio 會將檔案識別為 Python 程式碼,儘管使用 C++ 檔案範本。

    Visual Studio 會在程式碼編輯器中開啟新檔案。

  4. 將下列程式碼貼入新檔案。 選擇與您的擴充方法對應的程式碼版本:

    • CPython 擴充功能 (superfastcode 專案):

      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 專案):

      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. 在 C++ 專案中,建立第二個名為 pyproject.toml,然後貼上下列程式碼:

    [build-system]
    requires = ["setuptools", "wheel", "pybind11"]
    build-backend = "setuptools.build_meta"
    

    TOML (.toml) 檔案使用組態檔的 Tom's Existing,Minimal Language 格式。

  6. 若要建立副檔名,請在程式碼視窗標籤中的 pyproject.toml filename 上按一下滑鼠右鍵,然後選取 Copy Full Path。

    Screenshot that shows how to copy the full path to the py project toml file in Visual Studio.

    使用路徑前,請先從路徑中刪除 pyproject.toml 名稱。

  7. Solution Explorer,展開解決方案的 Python Environments 節點。

  8. 用滑鼠右鍵按一下作用中 Python 環境 (以粗體顯示),然後選取 Manage Python Packages。

    Python Environments 窗格開啟。

    如果已安裝必要的軟體套件,您會看到它在此窗格中列出。

    • 繼續之前,請選取封裝名稱旁邊的 X,以解除安裝它。

    Screenshot that shows how to uninstall a package in the Python Environments pane.

  9. Python Environments 窗格的搜尋方塊中,貼上複製的路徑,並從路徑結尾刪除 pyproject.toml 檔案名稱。

    Screenshot that shows how to enter the path in the Python Environments pane to install the extension module.

  10. 選取 Enter,從複製路徑的位置安裝模組。

    提示

    如果安裝因許可權錯誤而失敗,請將--user引數新增到命令結尾,然後再次嘗試安裝。

從 Python 呼叫 DLL

將 DLL 提供給 Python 後 (如上一節所述) ,就可以從 Python 呼叫superfastcode.fast_tanh和函superfastcode2.fast_tanh2數。 然後,您可以比較函式效能與 Python 實現。

請依照下列步驟從 Python 呼叫擴充模組 DLL:

  1. 在程式碼編輯器中開啟 Python 專案的 .py 檔案。

  2. 在檔案的結尾,加入下列程式碼,以呼叫從 DLL 匯出的方法,並顯示其輸出:

    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. 選取 Debug >Start Without Debugging,或使用+鍵盤捷徑 CtrlF5,即可執行 Python 程式。

    注意

    如果無法使用 Start Without Debugging 指令,請在 Solution Explorer 中,在 Python 專案上按一下滑鼠右鍵,然後選取 Set as Startup Project。

    當程式執行時,請注意 C++ 常式的執行速度比 Python 實作快約 5 到 20 倍。

    以下是典型的程式輸出範例:

    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. 嘗試增加變COUNT數,讓時間差異更明顯。

    C++ 模組的偵錯組建,其執行速度也比發行版本組建慢,因為偵錯組建的最佳化程度較低,而且包含各種錯誤檢查。 嘗試在組建組態之間切換以進行比較,但請記得更新您先前為發行組態設定的屬性。

位址處理速度與開銷

在輸出中,您可能會注意到 PyBind11 擴充速度不如C Python 擴充,儘管它應該比純 Python 實現更快。 出現差異的主要原因是使用 METH_O 標誌。 此旗標不支援多個引數、引數名稱或關鍵字引數。 PyBind11 會產生稍微更複雜的程式碼,以提供更類似 Python 的介面給呼叫端。 由於測試程式碼呼叫 500,000 次函式,結果會大幅增加開銷。

您可以將for回圈移入原生 Python 程式碼,進一步降低系統開銷。 此方法牽涉到使用反覆運算器通訊協定 (或針對函式參數為 PyBind11 py::iterable 類型) 來處理每個元素。 移除 Python 與 C++ 之間的重複轉換,是減少處理序列所耗費時間的有效方式。

疑難排解匯入錯誤

如果您在嘗試匯入模組時收到 ImportError 訊息,您可以使用下列其中一種方式加以解決:

  • 當您透過專案參考建置時,請確認您的 C++ 專案屬性符合為 Python 專案啟動的 Python 環境。 確認Include (.h) 和 Library (DLL) 檔案正在使用相同的資料夾位置。

  • 確定輸出檔案的名稱正確,例如 superfastcode.pyd。 不正確的名稱或副檔名會阻止匯入必要的檔案。

  • 如果您使用 setup.py 檔案安裝模組,請務必在為 Python 專案啟動的 pipPython 環境中執行指令。 當您在 Solution Explorer 中展開專案的活動 Python 環境時,您應該會看到 C++ 專案的專案,例如 superfastcode。

偵錯 C++ 程式碼

Visual Studio 可支援同時偵錯 Python 和 C++ 程式碼。 下列步驟說明 superfastcode C++ 專案的偵錯程式,但 superfastcode2 專案的程式相同。

  1. Solution Explorer,以滑鼠右鍵按一下 Python 專案,然後選取 Properties。

  2. Properties 窗格中,選取 Debug 頁籤,然後選取 Debug >Enable native code debugging 選項。

    提示

    當您啟用原生程式碼偵錯時, Python 輸出視窗可能會在程式完成後立即關閉,而不會暫停並顯示 Press any key to continue。 若要在啟用原生程式碼偵錯後強制暫停並提示,請將-i引數新增至 [Debug] 索引標籤上的 >[Run Interpreter Arguments] 欄位。這個引數會在程式碼執行後讓 Python 解譯器進入互動模式。 程式會等候您選取 +Crl Z +Enter,以關閉視窗。 另一種方法是在 Python 程式import os末尾新增和語os.system("pause")句。 此程式碼會複製原始暫停提示。

  3. 選取 File >Save (Ctrl +S ) 以儲存屬性變更。

  4. 在 Visual Studio 工具列上,將 Build 組態設定為 Debug。

  5. COUNT因為程式碼通常需要較長的時間才能在偵錯工具中執行,所以您可能想要將 Python project .py 檔案中的變數變更為比預設值小五倍的值。 例如,將它從 500000 變更為 100000

  6. 在 C++ 程式碼中,在方tanh_impl法的第一行設定中斷點。

  7. 選取 Debug >Start Debugging,或使用鍵盤快速鍵 F5,啟動除錯程式。

    呼叫中斷點程式碼時,偵錯工具會停止。 如果中斷點未命中,請檢查組態是否設定為 [Debug],以及您是否儲存專案,當您啟動偵錯程式時,不會自動發生這種情況。

    Screenshot of C++ code that contains a breakpoint in Visual Studio.

  8. 在中斷點,您可以逐步執行 C++ 程式碼、檢查變數等等。 如需這些功能的詳細資訊,請參閱一起偵錯 Python 和 C++

替代方法

您可以透過各種方式建立 Python 延伸模組,如下表所述。 本文將討論前兩個資料列 CPythonPyBind11

方法 年份 代表使用者
適用於 CPython 的 C/C++ 延伸模組 1991 標準程式庫
PyBind11 (建議用於 C++) 2015
Cython (建議用於 C) 2007 geventkivy
HPy 2019
mypyc 2017
ctypes 2003 oscrypto
cffi 2013 cryptographypypy
SWIG 1996 crfsuite
Boost.Python 2002
cppyy 2017