初用C/C++扩展Python,提高性能

发布时间:2020-09-26 07:32:55 作者:孤雁不独飞
来源:网络 阅读:4426

    前段时间写了两篇文章介绍如何提高Python的运行效率,一篇是从python语言本身的角度去介绍的,另一篇是从解释器角度(利用PyPy),有兴趣的可以找着看看。从另外一个角度来介绍如何提高python运行效率,那就是利用c/c++来扩展python提高性能。我们知道python官方网站上下载的python解释器源码是用c语言编写的,所以,也可以利用c/c++来扩展它,以获得较优的执行性能。Python提供了API接口,是我们很方便的能进行扩展,所有这些API都包含在Python.h的头文件里,在编写c代码时引入该头文件即可。下面来讲讲我初用c/c++扩展python的经历吧。申明所有系统Ubuntu 16.04 LTS。

一)Ubuntu下如何编译.c文件

    说实话,进行这部分学习时,第一困扰我的问题就是不知道怎么在Ubuntu下编译.c文件,以前在大学的时候,用的是Windows系统,安装了visual studio 2010,代码编写,编译都很方便。没有在Ubuntu下用c语言开发,所以这部分知道还不太了解,好在网上资料非常丰富,很快就能找到相应的资料。其实Ubuntu系统自带c语言编译器,那就是gcc。不信你可以打开终端,输入命名:gcc --version,显示如下信息:

初用C/C++扩展Python,提高性能

如果没有的话,你也可自己安装,安装命令如下:

sudo apt-get install gcc


建议还要安装一个build-essentiall包,作用是提供编译程序必须软件包的列表信息,也就是说 编译程序有了这个软件包它才知道 头文件在哪 ,才知道库函数在哪,还会下载依赖的软件包 , 最后才组成一个开发环境。

好了,现在写个简单的.c文件吧。

打开终端,输入命令vim hello.c,当然,你也可以用gedit来编辑代码,只要文件扩展名不搞错了就行。代码如下:

#include<stdio.h>
int main()
{
int i;
for(i=0;i<3;i++)
printf("hello,gcc!\n");
}

然后保存文件并退出。编译成可执行文件,命令如下:

gcc hello.c -o hello

然后输入./hello执行该文件。效果如下图。

初用C/C++扩展Python,提高性能

这里只是简单的讲了一下linux的gcc的使用方法,关于它更多的用法可以在网上查资料,在此不做过多介绍。


(二)使用C/C++扩展Python

1.先利用Python提供的接口,编写一个汉语一定功能.c文件,比如判断一个数是不是素数。在这里文件名为test.c,使用c语言实现后再使用Python进行包装。代码如下:

#include<Python.h>
static PyObject *pr_isprime(PyObject *self,PyObject *args){
    int n,num;
    if(!PyArg_ParseTuple(args,"i",&num))
        return NULL;
    if(num<1){
        return Py_BuildValue("i",0);
    }
    n=num-1;
    while(n>1){
        if(num%n==0)
            return Py_BuildValue("i",0);
            n--;
    }
    return Py_BuildValue("i",1);
}

static PyMethodDef PrMethods[]={
    {"isPrime",pr_isprime,METH_VARARGS,"check if an input numbe is prime or not."},
    {NULL,NULL,0,NULL}
};

void initpr(void){
    (void) Py_InitModule("pr",PrMethods);
}

PyObject是Python对象机制的基础,所有得对象都拥有一些相同的内容,而这些内容在PyObject中定义。

上面的代码包括三部分:

一是导出函数,C模块对外暴露的接口函数pr_isprime,带有self和args两个参数,其中参数args中包含了python解释器要传递给c函数的所有参数,通常使用PyArg_ParseTuple()来获得这些参数。

二是初始化函数,以便python解释器能够对模块进行初始化,初始化时要以init开头,如initx。

第三是方法列表,提供给外部的python程序使用的一个C模块函数名称映射表PrMethods。它是一个PyMethodDef结构体,其中成员依次表示方法名、导出函数、参数传递方式和方法描述。

参数传递方式一般设置为METH_VARARGS,如果想传递关键字参数,你可以让它与MRTH_KEYWORDS进行或运算;如果不想接受任何参数,可以用METH_NOARGS,该结构体必须以{NULL,NULL,0,NULL}所表示的一条空记录结尾。


至于为什么这样做,可能与Python.h里面的函数有关,该部分我还未仔细研究,所以这篇文章也叫题目用了“初用”,如果有以后弄清楚了,我会“再用”,与大家分享学习经验。


2.编写setup.py脚本

代码如下:

rom distutils.core import setup,Extension
module = Extension('pr',sources=['test.c'])
setup(name='Pr test',version = '1.0',ext_modules=[module])

 distutils包是可以用来在Python环境中构建和安装额外的模块。新的模块可以是纯Python的,也可以是用C/C++写的扩展模块,或者可以是Python包,包中包含了由C和Python编写的模块。在此不做过多介绍,有兴趣可以在网上找资料了解下。


3.使用python setup.py build进行编译,系统会自动在当前目录生成一个build子目录,里面包含一个.so文件、.o文件。看看我的操作结果吧

初用C/C++扩展Python,提高性能

执行python setup.py build命令后,系统确实在当前目录生成了一个build子目录,并且有一个.so文件、.o文件。

4.将生成的.so文件复制到/usr/local/lib/python2.7/dist-packages下,或者将.so文件所在目录路径添加到sys.path中,然后就可以使用该C扩展模块了。如下图:

初用C/C++扩展Python,提高性能


(三)简单测试下性能

代码如下:

#coding=utf-8
import pr
import datetime
def is_prime(n):
    if n <= 1:#
        return False
    else:
        a = n - 1
        while(a > 1):
            if n % a == 0:
                return True
            a = a - 1
        return False
t1 = datetime.datetime.now()
is_prime(8888888)
t2 = datetime.datetime.now()
pr.isPrime(8888888)
t3 = datetime.datetime.now()
print t3 - t2,t2 - t1

其中is_prime()是用python写的判断一个正数是不是素数。它的循环算法与pr模块里面的isPrime()是一样的,但是效率却有很大差异,看看下图运行结果。

初用C/C++扩展Python,提高性能

很显然用c扩展的那个包里的函数计算速度快而且是块近20倍,数值越大,速度上的差距越大,有兴趣的话,可以动手试下。当然这只是一个定性分析。

推荐阅读:
  1. 怎么在jQuery插件中使用FusionCharts绘制一个帕累托图效果
  2. 如何在NodeJs中使用Mocha测试框架

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

性能 扩展 python

上一篇:Vuex中的State使用介绍

下一篇:Spring Cloud实现提供API给客户端的方法详解

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》