您的位置:首页 > 编程语言 > Python开发

python c 扩展 ctype 以及 效率对比

2013-11-01 22:34 483 查看
python开发效率高,第三方库资源丰富,而且可以用C/C++扩展。(基于python官方文档)



今天研究了用C来写python的扩展,用的是2.x版本的,刚开始还弄错了,看的是3.x版本的文档,浪费了不少时间。

其实用c/c++写python的扩展,有至少四种方法:

1、原生python c api

2、ctypes

3、boost.python

4、swig

后面两种需要额外下载安装boost.python 或者 swig,更加麻烦,所以只是实验了前两种。

首先将用C/C++ 编写python扩展吧;

我是在widows下,用的 vs2010 express,新建一个win32 DLL工程

然后在源码里面增加下面代码,主要实现了add方法,实现返回累加值,比如输入100,返回 1加到100

注意:需要将python安装目录下的 include(头文件) 和 lib 文件夹(库文件) 加入工程目录,我用的python (x,y) 所以还加了 libs目录

最后可以编译了,编译成一个 *. dll 文件,改成 *.pyd 然后copy到 python 的lib文件夹下,这样就可以用了,

比如我这个工程叫做spam,编译成spam.dll,重命名为spam.pyd

#include <Python.h>
static PyObject *SpamError;
static PyObject *
spam_add(PyObject * self,PyObject *args)
{
	long a;
	//将python中传入的变量转化成C中的变量
	if(!PyArg_ParseTuple(args,"l",&a))
		return NULL;
	long long tmp=0;
	for(long i = 1;i<=a;i++)
		tmp +=i;
	//将C中的变量转化成python中的变量
	return Py_BuildValue("L",tmp);
}

//方法定义
static PyMethodDef SpamMethods[] = {
	 //每个方法都有四个属性
	 //分别为 1、python中方法名 2、c中名称
	 //3、应该就是传入的参数
	 //4、方法描述
	{"add",spam_add,METH_VARARGS,
	"Return the cumulative value "},
	//这个是必须加的,应该都一样吧
    {NULL, NULL, 0, NULL}        /* Sentinel */
};

//初始化模块
PyMODINIT_FUNC
initspam(void)
{
    PyObject *m;
	//参数:模块名称 ,方法数组
    m = Py_InitModule("spam", SpamMethods);
    if (m == NULL)
        return;
	//异常处理
    SpamError = PyErr_NewException("spam.error", NULL, NULL);
    Py_INCREF(SpamError);
    PyModule_AddObject(m, "error", SpamError);
}

以上,可以看出来用ctype写扩展,主要是三部分:

1.函数主体,需要实现变量 从python到 c,然后从 c到python的转换

2.定义方法,static PyMethodDef ,确定python中方法与c中方法的映射关系

3,初始化模块,



以上步骤完成后,可以开始测试一下c扩展作用有多大了。。

重启python ,

import spam 
dir(spam)


可以看到模块有一个方法叫做add



然后我们开始测试python 和c扩展模块的速度差别了:

用python和c返回1到 10000000 的累加和,c里面要用long long 存,不然会溢出哦~

各自计算10遍,然后算平均时间:

# -*- coding: utf-8 -*-
"""
Created on Thu Oct 31 20:59:38 2013

@author: peter
"""

import time
import spam

start = time.clock()

for i in xrange(10):
    spam.add(10000000)
t1 = (time.clock()-start)/10
print "c cost time:",t1

start = time.clock()

for j in xrange(10):
    tmp = 0
    for i in xrange(1,10000001):
        tmp +=i
t2 = (time.clock()-start)/10

print "python cost time:",t2
print "c is %f times faster "%(t2/t1)




c cost time: 0.0104223142169
python cost time: 2.59412283937
c is 248.900847 times faster


上面的方法太复杂了,用Ctype更简单,直接写一个C++的DLL,用Ctypes调用就ok了

windows下面注意在函数前加_declspec(dllexport),表示一个导出的函数





extern "C"
{
_declspec(dllexport) long long add(long x)
{
	long long y = 0;
	for(long a = 1;a<=x;a++)
		y+=a;
	return y;
}
}



然后在python 中调用,这里我生成的dll叫做TT.dll,把它拷贝到了python代码的所在目录

import ctypes

test =ctypes.CDLL('TT.dll');

print test.add(100)


it works



然后比较一下性能吧

# -*- coding: utf-8 -*-
"""
Created on Thu Oct 31 20:59:38 2013

@author: peter
"""

import time
import spam
import ctypes
# test c module
start = time.clock()

for i in xrange(10):
    spam.add(10000000)
t1 = (time.clock()-start)/10
print "c cost time:",t1
# test python 
start = time.clock()

for j in xrange(10):
    tmp = 0
    for i in xrange(1,10000001):
        tmp +=i
t2 = (time.clock()-start)/10

print "python cost time:",t2

# test ctype
test =ctypes.CDLL('TT.dll');
start = time.clock()

for i in xrange(10):
    test.add(10000000)
t3 = (time.clock()-start)/10
print "ctype cost time:",t3

start = time.clock()

print "c is %f times faster "%(t2/t1)
print "ctype is %f times faster "%(t2/t3)


运行结果:





c cost time: 0.0107829747003
python cost time: 2.6450129228
ctype cost time: 0.0125509386257
c is 245.295292 times faster 
ctype is 210.742240 times faster
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: