Python與C/C++互操作

來源:互聯網
上載者:User

標籤:return   extension   tuple   red   end   擴充   amp   初始   應用   

Python調用C/C++

Python調用C/C++的方法可以分為兩類:

  1. 手寫擴充模組:除了被調用的C/C++函數外,一般還需要編寫包裹函數、匯出表、匯出函數、編譯指令碼等代碼。

  2. 使用封裝庫的介面:比如官方的ctypes,還有第三方的如CFFI、Boost、SWIG、pybind11等。

最終在Python中都是通過載入動態連結程式庫的方式實現調用,手寫模組的方式更為複雜,但也更為高效。在實際工程中,一般對需要調用C/C++的函數(主要出於效能考慮)先通過ctypes實現,再有針對性地使用手寫模組的方式改寫。

ctypes

ctypes[文檔]是Python官方的一個提供C相容資料類型的外部函數庫,通過動態連結或共用庫的方式調用。

從原理上來說[文章]:ctypes直接調用二進位的動態連結程式庫(平台相容性差),在Windows下最終調用的是Windows API中的LoadLibrary函數和GetProcAddress函數,在UNIX平台下最終調用的是Posix標準中的dlopen和dlsym函數。ctypes實現了一系列的類型轉換方法,Python資料類型被封裝或直接推算為C類型,即手寫模組中的PyObject * <-> C types的轉換由ctypes內部完成。

手寫擴充模組

Python/C API Reference Manul

包裹函數:主要實現Python和C的參數轉換,以及對C函數的調用。

匯出表:告訴Python模組名,其中的被調函數名,以及對應的包裹函數和參數說明。

匯出函數:按照匯出表完成模組初始化。函數名必須以PyInit_為首碼。

Python和C之間的類型轉碼如下表所示。
| Format Code | Python Type | C Type |
| :-: | :-: | :-: |
| s | str | char * |
| z | str/None | char /NULL |
| i | int | int |
| l | long | long |
| c | str | char |
| d | float | double |
| D | complex | Py_Complex
|
| O | (any) | PyObject * |
| S | str | PyStringObject |

相比於ctypes,手寫擴充模組複雜得多,同時還可能帶來一些問題,如包裹函數中可能需要free()操作(防止記憶體流失)、對象引用計數的宏(Py_INCREF(), Py_DECREF(), Py_XINCREEF(), Py_XDECREF())、多線程的宏(Py_BEGIN_ALLOW_THREADS, Py_END_ALLOW_THREADS)等,因此對程式員要求較高。

實現與效能首先給出一個ctypes的例子。

編寫一個簡單的C程式fac.c實現階乘功能。

int fac(int n){    if (n < 2)        return 1;    return n * fac(n - 1);}

編譯產生動態連結程式庫。

gcc fac.c -fPIC -shared -o fac.so

在Python中調用。

from ctypes import cdlllibc = cdll.LoadLibrary(‘./fac.so‘)print(libc.fac(3)) # output 3! = 6
然後給出同樣功能的手寫擴充模組實現。

首先使用樣板(即介面)包裹上述階乘程式,使得應用程式代碼可以和Python解譯器進行互動。注意:Python2和Python3的介面略有不同,本文針對Python3。

int fac(int n){    if (n < 2)        return 1;    return n * fac(n - 1);}#include <Python.h>// 包裹函數static PyObject *ExFac(PyObject *self, PyObject *args){    int n;    // 參數轉換    // 根據指定格式解析並將結果放入指標變數,返回0表示解析失敗    if (!PyArg_ParseTuple(args, "i", &n))        return NULL;    // 把C資料轉換為Python對象並返回    return (PyObject *)Py_BuildValue("i", fac(n));}static PyMethodDef ExfunMethods[] = {    // 表示參數以tuple形式傳入    {"fac", ExFac, METH_VARARGS},    {NULL, NULL},};// 匯出表static struct PyModuleDef ExfunMethod = {    PyModuleDef_HEAD_INIT,    "exfun",    NULL,    -1,    ExfunMethods};// 匯出函數void PyInit_exfun(){    PyModule_Create(&ExfunMethod);}

把該模組編譯到Python中。

# setup.pyfrom distutils.core import setup, ExtensionMOD = ‘exfun‘setup(name=MOD, ext_modules=[Extension(MOD, sources=[‘exfun.c‘])])
python3 setup.py buildpython3 setup.py install

在Python中調用。

import exfunprint(exfun.fac(3)) # output 6

在Python中匯入並調用exfun.fac()後,包裹函數ExFac()被調用,接受一個Python的整型參數,並轉化為C的整型,然後調用C的fac()函數,得到一個整型傳回值,再轉為Python的整型作為整個函數調用的結果返回。

最後比較原生Python與上述兩種C調用的效能表現。

Python提供timeit模組來測量小程式碼片段的執行時間。以計算20的階乘為例,timeit預設執行1,000,000次。

from ctypes import cdllimport exfunimport timeitdef fac(n):    if n < 2:        return 1    return n * fac(n - 1)libc = cdll.LoadLibrary(‘./fac.so‘)print(timeit.timeit("fac(20)", setup="from __main__ import fac")) # 2.78sprint(timeit.timeit("libc.fac(20)", setup="from __main__ import libc")) # 0.39sprint(timeit.timeit("exfun.fac(20)", setup="from __main__ import exfun")) # 0.16s

需要注意的是,由於Python3中int對長整型的支援,計算20!時原生Python得到的是正確的結果,而調用C的都溢出了。

其他方法

如CFFI,
Boost,
SWIG,
pybind11。

C/C++調用Python

C/C++調用Python一般是為了利用指令碼開發的靈活性,類似於遊戲開發中Lua和C++的結合。在C++應用中,我們可以用一組外掛程式來實現一些具有統一介面的功能,一般外掛程式都使用動態連結程式庫實現。如果外掛程式的變化比較頻繁,我們就可以使用Python來代替動態連結程式庫形式的外掛程式,這樣可以方便地根據需求的變化改寫指令碼代碼,提高靈活性。

多語言程式分析工具

就像上面 實現與效能 一節中看到的,多語言的使用為指令碼語言帶來了巨大的效能提升,然而同時也提高了編程複雜度,潛藏記憶體流失、懸Null 參考等一系列問題,也增加了系統效能分析的難度。下面列舉一些可能有協助的工具。

  • Intel Pin: 使用動態二進位插樁的程式分析工具。

  • Pungi: 靜態分析Python的C擴充介面代碼的引用計數錯誤。(未開源,不適用於C++擴充)

  • CPyChecker: 在擴充模組中檢查一系列錯誤的gcc外掛程式。

  • Intel SEAPI (ITT API): 產生和控制應用程式執行過程中的跟蹤資料集合。

Python與C/C++互操作

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.