在Python中,为什么用C实现的模块比纯Python模块快,以及如何编写一个?
Python的文档提到,cPickle比Pickle快的原因是cPickle是用C语言实现的。这到底是什么意思呢?
我正在用Python做一个高级数学模块,有些计算花费的时间比较长。这是否意味着如果我的程序用C语言实现,就能变得更快呢?
我希望能像导入cPickle一样,从其他Python程序中导入这个模块。
你能解释一下如何用C语言实现一个Python模块吗?
5 个回答
当你在Python中写一个函数时,系统会创建一个新的函数对象。这个函数的代码会被解析并转换成字节码(并保存在“func_code”属性中),所以当你调用这个函数时,解释器会读取它的字节码并执行。
如果你在C语言中写同样的函数,并按照C/Python的接口让它在Python中可用,解释器会创建这个函数对象,但这个函数就没有字节码了。当解释器发现调用这个函数时,它会直接调用真正的C函数,因此执行速度是“机器”速度,而不是“Python机器”速度。
你可以通过检查用C语言写的函数来验证这一点:
>>> map.func_code
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'builtin_function_or_method' object has no attribute 'func_code'
>>> def mymap():pass
...
>>> mymap.func_code
<code object mymap at 0xcfb5b0, file "<stdin>", line 1>
要了解如何为Python编写C代码,可以参考官方网站上的指南。
不过,如果你只是进行N维数组的计算,使用numpy就足够了。
正如之前提到的,numpy在处理向量计算方面非常出色。(虽然它还有提升的空间,但确实比你自己写的代码要好得多,尤其是在不想花太多时间的情况下。)
不过,并不是所有的计算都能轻松地用向量化的方法来处理,所以如果你有一些紧密的循环,里面有很多函数调用(比如一个复杂的递归算法),你还有其他选择:最受欢迎的选择可能是Cython,它允许你用一种带注释的Python来写模块和函数,这样在需要的时候就能获得接近C语言的速度。
或者,也许你的计算时间主要花在调用库函数上,比如计算特征值、求逆矩阵、评估特殊函数,或者处理非常大的整数——顺便提一下,如果你做的事情更偏向数学而不是单纯的计算,Sage项目在这方面表现得非常好——在这种情况下,你在Python中花费的时间可能并不重要。这一切都取决于你具体在做什么样的数值计算。
你可以写快速的C语言代码,然后在你的Python脚本中使用它,这样你的程序运行起来会更快。
一个例子就是Numpy,它是用C语言写的(https://numpy.org/)。
通常的做法是把程序中最耗时的部分用C语言实现(或者使用一些用C写的库,当然;),然后用Python来写其他的代码。
顺便说一下,这就是为什么cPickle比pickle快的原因。
补充一下:
可以看看Pyrex:http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/version/Doc/About.html
“Pyrex是一种专门为编写Python扩展模块而设计的语言。它旨在弥合Python这个高层次、易于使用的世界和C语言这个低层次、复杂的世界之间的差距。”
这不是“官方”的方式,但可能会很有用。