Python与C++联合编程的简介
作为Python程序员,应该能够正视Python的优点与缺点。众所周之,Python的运⾏速度是很慢的,特别是⼤数据量的运算时,Python会慢得让⼈难以忍受。对于这种情况,“专业”的解决⽅案是⽤上numpy或者opencl。不过有时候为了⼀点⼩功能⽤上这种重型的解决⽅案很不划算,或者有时候想要实现的操作在numpy⾥⾯没有,需要我们⾃⼰⽤C语⾔来编写。总之,我们使⽤Python与C++的混合编程能够加快程序热点的运算速度。
⾸先要提醒⼤家注意的是,在考虑联合编程之前⼀定要到程序运⾏的热点。简单⼀点地,使⽤标准库的profile或者cProfile模块到最消耗CPU的位置,如果这个位置只简单的消耗IO时间,通常换成C++程序的意义也不会很⼤,此时做联合编程可能是事倍功半,起不到多⼤的效果。
编程先学c语言还是python
还有些情况,Python程序员们想要使⽤操作系统或者外部模块提供的函数。这些模块⼀般是为C/C++程序员提供的。这时候也是Python与C++联合编程的⽤武之地。
Python语⾔可以说是最好的胶⽔语⾔。仅就与C++联合编程这个问题来讲,依使⽤难度与功能来排列,Python社区提供了以下⼏种解决⽅案:
1. 使⽤标准库ctypes直接调⽤C/C++编写的动态链接库。这是最简单易⽤的⽅案。C/C++程序员使⽤⾃⼰的丰富的经验,把预定的功
能实现为动态链接库。⽽Python程序员只要知道这些动态链接库函数的名称、参数类型与返回值类型就能简单地调⽤它。当你传⼊参数时,ctypes模块会⾃动地把Python的对象成为C/C++所对应的参数类型。⽐如以下调⽤Windows的API:
#定义参数类型与函数名称
from ctypes.wintypes import UINT, DWORD
GetLastInputInfo = ctypes.windll.user32.GetLastInputInfo
class LASTINPUTINFO(ctypes.Structure):
_fields_ =[("cbSize", UINT),
("dwTime", DWORD)]
#开始调⽤DLL导出的函数
def getLastInputTime_nt():
info = LASTINPUTINFO()
info.cbSize = ctypes.sizeof(info)
info.dwTime =0
if not GetLastInputInfo(ctypes.byref(info)):
raise WindowsError("")
return info.dwTime
在这⾥展⽰了如何构造Windows的API所需要的结构体,如何填充结构体并分析返回值。
ctypes还能将Python函数提供给C/C++代码作为回调函数。
与其它解决⽅案相⽐。ctypes不需要程序员熟悉C/C++语⾔,不需要安装⼀个C/C++的编译器,它通过操作系统的接⼝直接操作C/C++代码。⽽且ctypes是标准库的⼀部分,只要安装了Python就可以直接使⽤。这⼏个原因使得它深受Python程序员的喜爱。
⽽它的劣势呢。⾸先,ctypes不能简单调⽤C++程序,因为C++在编译的时候使⽤了name mangling这个技术来实现函数的重载。
C++会⾃动地为类的成员函数加上类名前缀。所以,C++程序员需要以C语⾔的调⽤约定来提供接⼝,没有类,没有重载函数,没有模板,没有C++异常。不能直接调⽤现有的C++代码可能是这个⽅案最⼤的缺点。
另外,对于list, set之类的数据类型,ctypes不能识别并⾃动地在Python与C/C++数据类型之间转换。C/C++部分不能识别Python数据类型,这时候只能⽤Python语⾔来编写转换代码。如果数据量较⼤,或者调⽤很频繁,转换代码反⽽会浪费很多的资源。这或许是ctypes的另⼀个劣势之⼀了。
2. 如果你使⽤的是Jython或者IronPython的话,它们也提供了类似于ctypes之类的模块,能够直接访问Java或者.Net语⾔编写的模
块。其优势与劣势⼤致与ctypes相似。因为其使⽤范围有限,这⾥不再详述。
3. 使⽤Cython语⾔,⼀种类似于Python语⾔的⼀种新型语⾔编写预定功能的代码,然后将这些代码转换成为C语⾔编译成为Python语
⾔可以直接调⽤的⼆进制模块。Cython语⾔是融合Python语⾔与C语⾔的⼀种新型语⾔。它本⾝能够理解Python语⾔的语法,然后在其基础上增加了某些C语⾔的语法,以便更精细地控制数据类型与指针。基本兼容Python语法是这个解决⽅案最⼤的特点。很多时候,Python程序员只要在旧的代码中简单地声明⼀下代码中所使⽤的参数、变量的类型,就能把⽴即为旧的Python程序提速。
Cython提供了⼀个名为pyximporter的⼯具,能够在安装了C/C++编译器的计算机上⾯为简单的Cython程序直接⽣成相应的Python 模块。这使得Cython的使⽤与普通的Python程序⼀样简单。⽐如下⾯这段代码,直接保存为myhello.pyx即可被调⽤。
#myhello.pyx
def sayHelloTenTimes():
cdef int i #只要简单地为变量标识类型即可加速循环。
for i in range(0, 10):
print("hello, world!")
$ python
>>> import pyximport; pyximport.install()
>>> import myhello
>>> myhello.sayHelloTenTimes()
由此可见,Cython⾮常容易使⽤。⽽且不仅能够处理C语⾔的模块,还能处理C++的模块——虽然没有直接⽀持虚函数之类的完整C++特性。因为它不直接使⽤C/C++语法,⽽是另外设计⽐C/C++更简洁优雅的新型语法,因此,对于不熟悉C/C++的程序员来说有很⼤的吸引⼒。相⽐ctypes来说,因为参数类型转换更加智能与⾼效,所以通常能够提升更多的效率。
劣势呢,所谓⽤Python程序员所熟练的语法来编写⾼速的运算代码,乍⼀听相当地有吸引⼒。但是如果想要更深⼊地控制内存与数据结构时,程序员可能会发现,现在他不得不熟练地掌握C/C++语⾔,然后⽤Cython的语法写出来。以程序员们懒惰的性格,这反⽽是件难以忍受的事件。这或许是Cython本⾝并不⼤流⾏的主要原因吧。
4. 使⽤boost.python。有意思的是,与ctypes/Cython形成鲜明的对⽐,boost.python倾向于让C++程序员拥有更熟悉的编程环境。它
让C++程序员使⽤他所熟悉的C++语法直接控制Python的数据结构,调⽤Python的解释器。它没有像Cython那样发明新的语法,⽽是直接使⽤C++的语法,编写供Python使⽤的接⼝。与Cython同样的道理,它的效率优胜于ctypes。
与Cython/SWIG/SIP等⽅案相⽐,程序员只需要学习C/C++与Python两种语⾔。另外,与本⽂提到的⼏种解决⽅案相⽐,它⾮常适合在主要由C++编写的程序中控制Python代码。不仅功能更强⼤、效率
还更⾼。如此神奇的解决⽅案会有什么劣势呢?某些⼈可能不同意吧,⽼鱼⼀听说它依赖于boost就蔫了,感觉编译与学习庞⼤⼜奇怪的boost⾮常浪费⽣命。
5. 使⽤SWIG或者SIP,通过编写⼀个接⼝⽂件,使⽤类似于C/C++语法——声明函数、类型的信息,然后使⽤特殊的⼯具为C/C++的
代码⽣成Python的接⼝代码。这些接⼝代码能够在Python与C/C++之间的数据结构转换。最终编译这些接⼝代码,成为Python的⼆进制模块。SWIG与SIP的接⼝⽂件与C/C++的头⽂件⾮常相似。
这两种⼯具差不多,因为。本质上,他们都与Cython类似,都使⽤了中间语⾔来⽣成转换代码。但SWIG/SIP能够在他们的接⼝⽂件中嵌⼊C/C++,能够让程序员仔细地调节数据类型的转换过程。在使⽤上,它⽐Cython的层次更低,更接近于Python本⾝提供的API。
SWIG能够为多种脚本语⾔⽣成转换代码。⽽SIP则专门针对Python与C++。此外,SIP本⾝是作为PyQt的专门⼯具来开发的,因此它能够理解Qt的signal/slot。从应⽤项⽬上来看,SWIG似乎会更⼴泛⼀点。⽽SIP,⽬前所见的项⽬基本都与PyQt相关。据说
SWIG对于C++的⽀持不好,不知道有没有⼈来说⼀下呢。相⽐之下,SIP对于C++的⽀持⾮常完善,诸如虚函数、protected
member function、模版、析构函数、异常等特性都得到良好的⽀持。⽽且SIP⽀持Python的GIL,还拥有⼀个使⽤Python编写的编译系统。可能会更⽅便⼀点。
然⽽这种⽅案毕竟要学习⼀种新的语⾔,所以从表⾯上来看不如Cython和boost.python讨喜。当程序员想要仔细地调节类型转换代码的时候,需要学习SWIG/SIP的内部机制,被限定使⽤特殊的变量名。这使得这种⽅案的学习曲线相对较⾼。
6. 直接使⽤Python的API,可以称之为最终解决⽅案。Cython, SWIG, SIP的接⼝⽂件转换后所⽣成的C/C++代码实际上都使⽤Python
的API。与其它⽅案相⽐,这种⽅案相当地繁复,必须为每次函数调⽤编写数据转换代码,还要操⼼Python对象的引⽤计数。我觉得这种⽅案⼀⽆是处,这时就不再多讲了。其它的⼯具不知道什么情况。有兴趣的话可以看看。
好了。题外话⼀句吧,我⼀直觉得ctypes与xmlrpc并列Python语⾔的两⼤神器,最能体现Python的⽣产效率。
希望本⽂在⼤家选择⼀种技术路线时能提供⼀点点帮助。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。