美文网首页python
<cython>学习笔记第一章:概要

<cython>学习笔记第一章:概要

作者: Stansosleepy | 来源:发表于2015-06-09 15:23 被阅读597次

    Cython第一章,概要


    开一个新坑,写点关于《Cython》的读书笔记
    这本书暂时还没有中译吧,我看起来还是有点吃力,
    全书的示例代码在:https://github.com/cythonbook/examples,最好配合起来看。

    cython的目的是要将python和c/c++结合起来,
    python是一种高层级的,动态的,解释性的,易学的语言,但是其带来的副作用是,运行效率可能会比静态编译语言慢几个数量级。我们可以使用python调用外部接口的方式,极大的提高python的运行效率。

    对比Python,C和Cython

    cython、c语言扩展python、纯python、纯c代码他们之间的运行效率究竟有多少差异,我们通过实例来对比一下。
    位置:/examples/01-essentials/03-timings

    我们先来看setup.py

    from distutils.core import setup, Extension
    from Cython.Build import cythonize
    
    exts = ([Extension("cfib", sources=["cfib.c", "cfib_wrap.c"])] +
            cythonize("cyfib.pyx") +
            cythonize([Extension("wrap_fib", sources=["cfib.c", "wrap_fib.pyx"])])
            )
    
    setup(
        ext_modules = exts,
    )
    

    setup.py中编译了三个动态库,

    1. cfib.c + cfib_wrap.c->cfib.so (使用纯c代码编写的python扩展)
    2. cyfib.pyx ->cyfib.so(使用cython语法生成python扩展)
    3. cfib.c + wrap_fib.pyx-> wrap_fib.so(使用cython包装了cfib.c生成python扩展)(这个库没有用来进行性能比较)

    再分析Makefile

    .PHONY : all
    all:
        python setup.py build_ext -if
        gcc -O3 cfib.c main.c -o cfib.x
    
    .PHONY : clean
    clean:
        -rm -r build *.so *.pyc cyfib.c *.x wrap_fib.c
    

    make的时候调用setup.py,同时也编译了cfib.c和main.c为一个可执行文件cfib.x。继续看cfib.c:

    #include "cfib.h"
    //计算斐波那契数列的第n个值
    double cfib(int n) {
        int i;
        double a=0.0, b=1.0, tmp;
        for (i=0; i<n; ++i) {
            tmp = a; a = a + b; b = tmp;
        }
        return a;
    }
    

    看main.c:

    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    #include "cfib.h"
    
    int main(int argc, char **argv) {
        int arg=-1, numiter=-1, i;
        clock_t t;
    
        if (argc != 3) {
            printf("Wrong number of arguments, expecting 2 (got %d)\n.", argc-1);
            return 1;
        }
    
        arg = atoi(argv[1]);
        numiter = atoi(argv[2]);
    
        t = clock();
        for (i=0; i<numiter; ++i) {
            cfib(arg);
        }
        t = clock() - t;
        printf("%f\n", ((float)t) / CLOCKS_PER_SEC / numiter * 1e9);
    
        return 0;
    }
    

    可以看出main.c接受两个参数,调用cfib(arg)循环numiter次,然后的到总时间并计算出每次计算斐波那契数的平均时间,用纳秒来表示(10的-9次方秒),现在我们确定了cfib.x程序的作用。

    需要对比以下四个库的效率,每个库都将计算fib(90)的值循环10万次,统计出每次fib计算的平均时间(纳秒)

    1. fib.py (纯python计算斐波那契数)
    2. cfib.c + cfib_wrap.c->cfib.so (使用纯c代码编写的python扩展)
    3. cyfib.pyx ->cyfib.so(使用cython语法生成python扩展)
    4. cfib.c + main.c ->cfib.x (纯c)

    执行

    make
    python timings.py
    

    在我的机器上计算的结果为:

    纳秒
    1.纯python:408
    2.纯C扩展python模块cfib.so:139
    3.Cython扩展python模块cyfib.so:62
    4.纯C语言cfib.x:4
    

    可以看出,对于计算斐波那契数这样的消耗cpu的运算来说,python比纯C语言程序慢两个数量级,手工使用python的C语言API进行扩展不如使用cython(因为cython对其进行了优化),cython对python的扩展可以提高1个数量级的效率

    使用cython包装c代码(好像前面一个小结也设计到这个内容了)

    查看对应位置的5个源文件,其中setup和Makefile都不是必须的,必要的时候可以自己编译,我们的目标是将wrap_fib.pyx 编译成wrap_fib.so,python可以直接import wrap_fib

    位置:/examples/01-essentials/02-wrapping-c-code-with-cython/

    源代码
    cfib.h  cfib.c  wrap_fib.pyx setup.py Makefile 
    -----------------
    cfib.h
    #ifndef __CFIB_H__
    #define __CFIB_H__
    double cfib(int n);
    #endif
    -----------------
    cfib.c
    #include "cfib.h"
    double cfib(int n) {
        int i;
        double a=0.0, b=1.0, tmp;
        for (i=0; i<n; ++i) {
            tmp = a; a = a + b; b = tmp;
        }
        return a;
    }
    ------------------
    wrap_fib.pyx
    cdef extern from "cfib.h":
        double cfib(int n)
    
    def fib(n):
        ''' Returns the nth Fibonacci number.'''
        return cfib(n)
    -------------------
    setup.py
    from distutils.core import setup, Extension
    from Cython.Build import cythonize
    #Extention:wrap_fib(c扩展的名字),source:一个源码文件的列表
    exts = cythonize([Extension("wrap_fib", sources=["cfib.c", "wrap_fib.pyx"])])
    
    setup(
        ext_modules = exts,
    )
    -------------------
    Makefile
    .PHONY : all
    all:
            python setup.py build_ext -if
    
    .PHONY : clean
    clean:
            -rm -r build *.so wrap_fib.c
    

    在cython中,我们将.pyx转化为.c,再编译成.so共享库,使用了python自带的distutils进行.c->.so的编译,有了以上这5个文件,再执行make,会发现文件夹里多了build/,wrap_fib.c,wrap_fib.so,其中wrap_fib.so为我们的目标库,可以直接被python引用。

    相关文章

      网友评论

      本文标题:<cython>学习笔记第一章:概要

      本文链接:https://www.haomeiwen.com/subject/etkjqttx.html