日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

c语言 python rsa库_Python遇到性能瓶颈怎么办?

發布時間:2025/10/17 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言 python rsa库_Python遇到性能瓶颈怎么办? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在Python遇到性能瓶頸時怎么辦?

答案是找對應功能的C/C++程序,把它編譯成CPython模塊,供Python調用來提高性能。

比如Python中做科學計算,數據處理的Numpy模塊就是使用C語言編寫的,Numpy處理速度比Pandas快數倍。Numpy的處理速度一點都不比go語言差。

本文就是介紹如何把C/C++程序編譯成Python模塊。本文偏技術,需要耐著性質看。

Python 作為一個膠水語言,可以很方便的通過C/C++來進行擴展,提高性能。前面我寫了一篇文章介紹如何通過Python的ctypes加載普通的.so庫:

《Python的C/C++擴展之Python直接調用科大訊飛語音識別動態庫》

其實,這還不算真正的用C/C++寫Python的擴展模塊。

本文將介紹如何使用C語言和C++寫Python模塊。

一、Python的C語言接口

Python語言最初是用C語言實現的一種腳本語言,后來被稱為CPython,是因為后來又有其它語言實現的Python,比如Python實現的Python——PyPy,Java語言實現的Python——Jython,.Net實現的Python——IronPython。

CPython具有優良的開放性和可擴展性,并提供了方便靈活的應用程序接口(API),從而使得C/C++程序員能夠對Python解釋器的功能進行擴展。

Python的C語言接口很適合封裝C語言實現的各種函數,如果要封裝C++的類,使用boost_python或者SWIG更方便和合適,還有一個類似boost_python的支持C++11的pybind11

1 模塊封裝

假設我們有一個C函數:

/* 文件名:mylib.c */int addone(int a) {return a+1;
}

如果想在Python解釋器中調用該函數,則應該首先將其實現為Python中的一個模塊,這需要編寫相應的封裝接口,如下所示:

/* wrap_mylib.c */#include #include "mylib.h"
PyObject* wrap_addone(PyObject* self, PyObject* args)
{int n, result;if (! PyArg_ParseTuple(args, "i:fact", &n))return NULL;
?result = addone(n); /*這里調用C函數 */return Py_BuildValue("i", result);
}static PyMethodDef mylibMethods[] =
{
?{"addone", wrap_addone, METH_VARARGS, "Add one to N"},
?{NULL, NULL}
};void initmylib()
{
?PyObject* m;
?m = Py_InitModule("mylib", mylibMethods);
}

上面就是一個典型的Python擴展模塊,它至少應該包含三個部分:導出函數、方法列表和初始化函數。

2 導出函數

要在Python解釋器中調用C語言中的某個函數,首先要為它編寫對應的導出函數,上述例子中的導出函數為wrap_addone。在Python的C語言擴展中,所有的導出函數都具有相同的函數原型:

PyObject* wrap_method(PyObject* self, PyObject* args);

這個函數是Python解釋器和C函數進行交互的接口,一般以wrap_開頭后面跟上C語言的函數名,這樣命名把導出函數和C語言函數對應起來使得代碼更加清晰。它帶有兩個參數:self和args。

參數self?只在C函數被實現為內聯方法(built-in method)時才被用到,通常該參數的值為空(NULL)。參數args?中包含了Python解釋器要傳遞給C函數的所有參數,通常使用Python的C語言擴展接口提供的函數PyArg_ParseTuple()來獲得這些參數值。

所有的導出函數都返回一個PyObject指針,如果對應的C函數沒有真正的返回值(即返回值類型為void),則應返回一個全局的None對象(Py_None),并將其引用計數增1,如下所示:

PyObject* wrap_method(PyObject *self, PyObject *args)
{
?Py_INCREF(Py_None);return Py_None;
}

3 方法列表

方法列表中列出了所有可以被Python解釋器使用的方法,上述例子對應的方法列表為:

static PyMethodDef mylibMethods[] =
{
?{"addone", wrap_addone, METH_VARARGS, "Add one to N"},
?{NULL, NULL}
};

方法列表中的每項由四個部分組成:

  • 方法名

  • 導出函數

  • 參數傳遞方式

  • 方法描述

方法名是從Python解釋器中調用該方法時所使用的名字。
參數傳遞方式則規定了Python向C函數傳遞參數的具體形式,可選的兩種方式是METH_VARARGS和METH_KEYWORDS,其中METH_VARARGS是參數傳遞的標準形式,它通過Python的元組在Python解釋器和C函數之間傳遞參數,若采用METH_KEYWORD方式,則Python解釋器和C函數之間將通過Python的字典類型在兩者之間進行參數傳遞。

4 初始化函數

所有的Python擴展模塊都必須要有一個初始化函數,以便Python解釋器能夠對模塊進行正確的初始化。Python解釋器規定所有的初始化函數的函數名都必須以init開頭,并加上模塊的名字。對于模塊mylib來說,則相應的初始化函數為:

void initmylib()
{
?PyObject* m;
?m = Py_InitModule("mylib", mylibMethods);
}

當Python解釋器需要導入該模塊時,將根據該模塊的名稱查找相應的初始化函數,一旦找到則調用該函數進行相應的初始化工作,初始化函數則通過調用Python的C語言擴展接口所提供的函數Py_InitModule(),來向Python解釋器注冊該模塊中所有可以用到的方法。

5 編譯鏈接

要在Python解釋器中使用C語言編寫的擴展模塊,必須將其編譯成動態鏈接庫的形式。下面以Linux為例,介紹如何將C編寫的Python擴展模塊編譯成動態鏈接庫:

$ gcc -fpic -shared -o mylib.so \
? ? ? ? ? ? -I/usr/include/python2.7 \
? ? ? ? ? ?mylib.c wrap_mylib.c

6 在Python中調用

上面編譯生成的Python擴展模塊的動態鏈接庫,可以在Python中直接import。如下所示:

veelion@gtx:~$ python
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.>>> import example>>> example.addone(7)8
>>>

這里生成的.so動態庫和上一篇中不用Python的C語言生成的動態庫是不一樣的,從生成過程和使用方法就可以看出來,這里的動態庫使用起來感覺就是一個Python模塊,直接import就可以了。

二、用boost_python庫封裝C++類

安裝boost python庫:

sudo aptitude install libboost-python-dev

示例

下面代碼簡單實現了一個普通函數maxab()和一個Student類:

#include #include int maxab(int a, int b) { return a>b?a:b; }class Student {private:int age;
? ? ? ?std::string name;public:
? ? ? ?Student() {}
? ? ? ?Student(std::string const& _name, int _age) { name=_name; age=_age; }static void myrole() { std::cout << "I'm a student!" << std::endl; }void whoami() { std::cout << "I am " << name << std::endl; }bool operator==(Student const& s) const { return age == s.age; }bool operator!=(Student const& s) const { return age != s.age; }
};

使用boost.python庫封裝也很簡單,如下代碼所示:

#include #include #include #include #include "student.h"using namespace boost::python;
BOOST_PYTHON_MODULE(student) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// This will enable user-defined docstrings and python signatures,// while disabling the C++ signatures
? ?scope().attr("__version__") = "1.0.0";
? ?scope().attr("__doc__") = "a demo module to use boost_python.";
? ?docstring_options local_docstring_options(true, false, false);
? ?def("maxab", &maxab, "return max of two numbers.\n"
? ? ? ); ?
? ?class_("Student", "a class of student")
? ? ? ?.def(init<>())
? ? ? ?.def(init<:>string, int>())// methods for Chinese word segmentation
? ? ? ?.def("whoami", &Student::whoami, "method's doc string..."
? ? ? ? ? ?) ?
? ? ? ?.def("myrole", &Student::myrole, "method's doc string..."
? ? ? ? ? ?) ?
? ? ? ?.staticmethod("myrole");// 封裝STL
? ?class_<:>vector >("StudentVec")
? ? ? ?.def(vector_indexing_suite<:>vector >())
? ? ? ?; ?
}

上述代碼還是include了Python.h文件,如果不include的話,會報錯誤:

wrap_python.hpp:50:23: fatal error: pyconfig.h: No such file or directory

編譯

編譯以上代碼有兩種方式,一種是在命令行下面直接使用g++編譯:

g++ -I/usr/include/python2.7 ?-fPIC wrap_student.cpp -lboost_python -shared -o student.so

首先指定Python.h的路徑,如果是Python 3的話就要修改為相應的路徑,編譯wrap_student.cpp要指定-fPIC參數,鏈接(-lboost_python)生成動態庫(-shared)。生成的student.so動態庫就可以被python直接import使用了

In [1]: import student
In [2]: student.maxab(2, 5)
Out[2]: 5
In [3]: s = student.Student('Tom', 12)
In [4]: s.whoami()
I am Tom
In [5]: s.myrole()
I'm a student!

另外一直方法是用python的setuptools編寫setup.py腳本:

#!/usr/bin/env pythonfrom setuptools import setup, Extension
setup(name="student",
? ?ext_modules=[
? ?Extension("student", ["wrap_student.cpp"], ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ?libraries = ["boost_python"])
])

然后執行命令編譯:

python setup.py build
orsudo python setup.py install

三、SWIG封裝C++類

Python調用C/C++代碼的利器除了boost_python外,還有SWIG(Simplified Wrapper and Interface Generator),它是用來為腳本語言調用C和C++程序的軟件開發工具,它實際上是一個編譯器,獲取C/C++的聲明和定義,用一個殼封裝起來,以便其它腳本語言訪問這些聲明。所以,SWIG 最大的好處就是將腳本語言的開發效率和 C/C++ 的運行效率有機的結合起來。

一個雙數組Trie Tree的實現:cedar在中文分詞、新詞發現等算法中可以y用于詞典的創建。本文以cedar的SWIG封裝實現來說明SWIG的使用。

0. 安裝swig

工欲善其事必先利其器,首先要安裝swig,Ubuntu安裝swig很簡單:

sudo aptitude install swig

1. 聲明和定義C/C++代碼

在cedar的swig目錄下面有cedar的C++聲明和實現代碼trie.h,但是這個實現里面沒有遍歷所有key的函數方法,所以我添加了一個實現,首先定義一個數據結構來定義key:

// key-value pair return type for next_key()class kv_t {public:
? ? ? ?std::string key;int value;
};

添加一個函數每次返回一個key,當key字符串為空時表示遍歷結束,繼續調用的話就又從頭開始遍歷:

?// to iterate all keys
?kv_t next_key() const {static size_t from = 0, p = 0;union { int i; int x; } b;char key[256] = {0};
? ?kv_t kv;if(from == 0) {
? ? ? ?b.i = _t->begin(from, p);
? ?}else{
? ? ? ?b.i = _t->next(from, p);
? ?}if (b.i == trie_t::CEDAR_NO_PATH) {
? ? ? ?kv.key = "";
? ? ? ?kv.value = 0;
? ? ? ?from = 0;
? ? ? ?p = 0;return kv;
? ?}
? ?_t->suffix(key, p, from);
? ?kv.key = key;
? ?kv.value = b.x;return kv;
?}

2. 編寫接口文件.i

查看cedar.i可以看到SWIG的接口文件的編寫規則:

  • 首先在 %module ?后面聲明模塊名稱,這就是Python在import時使用的模塊名稱;

  • 在%{ … %}之間包含相關頭文件

  • 在%include 后面可以聲明對STL的支持

  • 最后聲明要封裝的函數和變量,也可以之間包含頭文件:%include “trie.h”

  • 3. 封裝代碼

    可以在Makefile里面看到python-bindings:

    python-bindings:
    ? ? ? ?swig -Wall -python -builtin -outdir python -c++ cedar.i
    ? ? ? ?mv -f cedar_wrap.cxx python

    直接make或者單獨運行上面的swig命令,就可以生成cedar.py和cedar_wrap.cxx文件。

    4. 編譯生成動態庫

    編譯生成的cedar_wrap.cxx使用python distutils的setup,可以參考python/setup.py的編寫。setup.py的build如下:

    python setup.py build

    就會在當前目錄下面創建目錄build,下面生成lib.linux-x86_64-2.7/cedar.py 和 _cedar.so

    四、 pybind11封裝C++

    從pybind11的名字可以看出,它是用來封裝C++ 11代碼為Python模塊的庫。它的目標和用法都是想Boost_python庫看齊,但是它又比龐大的Boost庫精簡。我知道這個庫的時間不長,也沒有具體實踐過。以前都是寫C++,然后用boost封裝。但是,感覺pybind11更簡潔,所以下一個項目可以試試它。到時候再分享使用心得給大家。

    一個十年Python碼奴與運營汪的結合體

    長按掃碼關注

    總結

    以上是生活随笔為你收集整理的c语言 python rsa库_Python遇到性能瓶颈怎么办?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。