精华内容
下载资源
问答
  • cython

    千次阅读 2019-04-18 12:22:09
    Tensorflow-mask RCNNCython 编程入门简介准备cython注意事项cython 编程实践 Cython 编程入门 在学习和训练mask rcnn中发现用了cython编程,特此整理。 简介 Cython是一个快速生成Python扩展模块的工具,从语法...

    Cython 编程入门

    在学习和训练mask rcnn中发现用了cython编程,特此整理。

    简介

    Cython是一个快速生成Python扩展模块的工具,从语法层面上来讲是Python语法和C语言语法的混血,当Python性能遇到瓶颈时,Cython直接将C的原生速度植入Python程序,这样使Python程序无需使用C重写,能快速整合原有的Python程序,这样使得开发效率和执行效率都有很大的提高,还能加速程序的速度。

    准备

    方法1 官网下载安装,Cython官网地址是:http://cython.org/
    方法2 直接用在现有环境下直接用anaconda安装cython
    使用命令 conda install cython

    cython注意事项

    1…pyx中用cdef定义的东西,除类以外对.py都是不可见的;
    2.py中是不能操作C类型的,如果想在.py中操作C类型就要在.pyx中从python object转成C类型或者用含有set/get方法的C类型包裹类;
    3.虽然Cython能对Python的str和C的“char *”之间进行自动类型转换,但是对于“char a[n]”这种固定长度的字符串是无法自动转换的。需要使用Cython的libc.string.strcpy进行显式拷贝;
    4.回调函数需要用函数包裹,再通过C的“void *”强制转换后才能传入C函数。

    cython 编程实践

    方法一

    1 首先编写一个hello.pyx的脚本

    print('hello world')
    

    2 然后我们新建一个setup.py脚本,这个python文件的目的就是使用cython编译器去编译pyx成一个cython文件,代码很简单

    from distutils.core import setup
    from Cython.Build import cythonize
    
    setup(
        ext_modules=cythonize("hello_world.pyx")
    )
    

    3 执行setup.py脚本

    python setup.py build_ext --inplace
    

    这时候cython将我们的pyx文件解析成一个c文件和一个so文件(linux)或者pyd文件(windows)。这个so文件或者pyd文件就可以像普通的python文件一样,被import。

    import hello_world
    

    在这里插入图片描述

    方法二

    但是每次都需要写一个setup文件十分不方便,所以cpython提供了另一种解决方法

    import pyximport
    pyximport.install()
    import hello_world
    

    这样cython会默默帮我们编译好了,放在其他地方,灰常方便我们的使用。

    方法三

    1 首先编写一个hello.pyx的脚本

    print('hello world')
    

    2 然后我们新建一个setup.py脚本,这个python文件的目的就是使用cython编译器去编译pyx成一个cython文件,代码很简单

    from distutils.core import setup
    from Cython.Build import cythonize
    
    setup(
        ext_modules=cythonize("hello_world.pyx")
    )
    

    3 执行setup.py脚本

    python setup.py build_ext --inplace
    

    这时候cython将我们的pyx文件解析成一个c文件和一个so文件(linux)或者pyd文件(windows)。

    4 编写一个同名的py文件

    import sys, pkg_resources, imp
    
    def __bootstrap__():
      global __bootstrap__, __loader__, __file__
      __file__ = pkg_resources.resource_filename(__name__, 'hello world.so')
      __loader__ = None
      del __bootstrap__, __loader__
      imp.load_dynamic(__name__, __file__)
    
    __bootstrap__()
    

    这时候我们直接impor这个py文件就可以了。

    展开全文
  • Cython

    2021-01-16 22:48:41
    Cython 编译运行 Use setup.py file from setuptools import setup from Cython.Build import cythonize from Cython.Compiler import Options Options.docstring = False setup( name='Hello world app', ext...

    Cython

    编译运行

    • Use setup.py file
    from setuptools import setup
    from Cython.Build import cythonize
    from Cython.Compiler import Options
    
    Options.docstring = False
    
    setup(
        name='Hello world app',
        ext_modules=cythonize("hello.pyx", compiler_directives={'embedsignature': True}), # target .pyx file and compile options
        zip_safe=False,
    )
    

    如果是要传入多个文件,可以使用正则表达式匹配,eg. *.pyx 。或者使用一个字符串的列表包含。

    编译:

    python setup.py build_ext --inplace
    
    • Use pyximport

    • Use Jupyter Notebook

    %load_ext Cython
    
    # Start a new cell
    %%cython
    
    cdef int a = 0
    for i in range(10):
        a += i
    print(a)
    

    编译选项

    编译选项如上 setup.py 中所示,使用 Options 设置,参考

    compiler derctives 可以在 setup.py 中设置,或者是在 .pyx 文件顶部加入如下注释

    #cython: language_level=3, ...
    

    变量类型

    声明变量类型,可以声明几乎所有的 C 类型(数,指针,结构体,联合体)

    cdef int i # declare an integer
    

    函数类型声明

    cdef int func(int a, int b)
    
    cpdef int func(int a, int b)
    

    cdef 只能在 .pyx 内调用,无法向 Python 提供接口。cpdef 可以向 Python 提供接口。

    • C array
    cdef int p[1000]
    
    for i in p[:100]:
        if i % 10 == 0:
            a += i
    

    从官方给出样例中可以看出,数组是可以用 Python 切片并且循环的。与 C 相同,函数中声明的变量放在堆栈(stack)中,所以不要声明过大的数组。关于堆栈和堆,参考

    • string

    返回字符串

    from libc.stdlib cimport malloc
    from libc.string cimport strcpy, strlen
    
    cdef char* hello_world = 'hello world'
    cdef Py_ssize_t n = strlen(hello_world)
    
    
    cdef char* c_call_returning_a_c_string():
        cdef char* c_string = <char *> malloc((n + 1) * sizeof(char))
        if not c_string:
            raise MemoryError()
        strcpy(c_string, hello_world)
        return c_string
    

    不要在函数里面声明一个字符数组然后返回。因为这个字符数组是在函数栈里面,函数返回后就释放了。应该使用 malloc 动态分配空间后返回!!!

    函数调用

    通过头文件和链接库就可以随意调用 C 函数

    # Python 可以直接调用
    cdef extern from "add.h":
        cpdef int func(int, int)
      
    # Python 不可直接调用
    cdef extern from "add.h":
        int func(int, int)
    

    setup.py

    from setuptools import setup, Extension
    from Cython.Build import cythonize
    
    ext_modules = [
        Extension("space",
                  sources=["space.pyx"],
                  include_dis = ['./']
                  libraries=["add"],  # Unix-like specific
                  library_dirs = ['./']
                  ),
    ]
    
    setup(
        name='Hello world app',
        ext_modules=cythonize(ext_modules), 
        zip_safe=False,
    )
    

    将之前的 C 函数编译成动态链接库。然后在 .pyx 中导入头文件并声明函数。之后再 setup.py 中编译链接,就可以调用 C 函数。编译时Extension参数见此处

    展开全文
  • Cython tutorial

    2021-01-05 17:18:13
    Cython的概括、不同环境下的安装、数据类型、如何使用Numpy、如何使用C代码等等内容。
  • cython.zip

    2021-02-01 16:23:28
    cython.zip
  • cython-例子 简单的 cython 示例。 还包含用于比较的 f2py 示例。 运行“python setup.py build_ext --inplace”编译代码,运行“python test.py”运行测试。 3 GHz mac 上的示例测试输出: macpro:cython-...
  • Learning Cython Programming

    2018-12-26 10:42:55
    Cython is a tool that makes writing C extensions to Python as easy as writing Python itself. This is the slogan to which Cython conforms. For those who don't know what I am talking about, writing C ...
  • CythonCython 基本用法

    千次阅读 多人点赞 2017-07-11 20:42:49
    我一直非常喜欢 Python。当人们提到 Python 的时候,经常会说到下面两个优点: ...在天壤实习的时候,跟Cython打了不少交道,觉得这个工具虽然 Bug 多多,写的时候也有些用户体验不好的地方,但已经能极...

    我一直非常喜欢 Python。当人们提到 Python 的时候,经常会说到下面两个优点:

    1. 写起来方便
    2. 容易调用 C/C++ 的库

    然而实际上,第一点是以巨慢的执行速度为代价的,而第二点也需要库本身按照 Python 的规范使用 Python API、导出相应的符号。

    天壤实习的时候,跟 Cython 打了不少交道,觉得这个工具虽然 Bug 多多,写的时候也有些用户体验不好的地方,但已经能极大提高速度和方便调用 C/C++,还是非常不错的。这里就给大家简单介绍一下 Cython(注意区别于 CPython)。Cython 可以让我们方便地:

    • 用 Python 的语法混合编写 Python 和 C/C++ 代码,提升 Python 速度
    • 调用 C/C++ 代码

    例子:矩阵乘法

    假设我们现在正在编写一个很简单的矩阵乘法代码,其中矩阵是保存在 numpy.ndarray 中。Python 代码可以这么写:

    # dot_python.py
    import numpy as np
    
    def naive_dot(a, b):
        if a.shape[1] != b.shape[0]:
            raise ValueError('shape not matched')
        n, p, m = a.shape[0], a.shape[1], b.shape[1]
        c = np.zeros((n, m), dtype=np.float32)
        for i in xrange(n):
            for j in xrange(m):
                s = 0
                for k in xrange(p):
                    s += a[i, k] * b[k, j]
                c[i, j] = s
        return c
    

    不用猜也知道这比起 C/C++ 写的要慢的不少。我们感兴趣的是,怎么用 Cython 加速这个程序。我们先上 Cython 程序代码:

    # dot_cython.pyx
    import numpy as np
    cimport numpy as np
    cimport cython
    
    @cython.boundscheck(False)
    @cython.wraparound(False)
    cdef np.ndarray[np.float32_t, ndim=2] _naive_dot(np.ndarray[np.float32_t, ndim=2] a, np.ndarray[np.float32_t, ndim=2] b):
        cdef np.ndarray[np.float32_t, ndim=2] c
        cdef int n, p, m
        cdef np.float32_t s
        if a.shape[1] != b.shape[0]:
            raise ValueError('shape not matched')
        n, p, m = a.shape[0], a.shape[1], b.shape[1]
        c = np.zeros((n, m), dtype=np.float32)
        for i in xrange(n):
            for j in xrange(m):
                s = 0
                for k in xrange(p):
                    s += a[i, k] * b[k, j]
                c[i, j] = s
        return c
    
    def naive_dot(a, b):
        return _naive_dot(a, b)
    

    可以看到这个程序和 Python 写的几乎差不多。我们来看看不一样部分:

    • Cython 程序的扩展名是 .pyx
    • cimport 是 Cython 中用来引入 .pxd 文件的命令。有关 .pxd 文件,可以简单理解成 C/C++ 中用来写声明的头文件,更具体的我会在后面写到。这里引入的两个是 Cython 预置的。
    • @cython.boundscheck(False) 和 @cython.wraparound(False) 两个修饰符用来关闭 Cython 的边界检查
    • Cython 的函数使用 cdef 定义,并且他可以给所有参数以及返回值指定类型。比方说,我们可以这么编写整数 min 函数:

        cdef int my_min(int x, int y):
            return x if x <= y else y
      

      这里 np.ndarray[np.float32_t, ndim=2] 就是一个类型名就像 int 一样,只是它比较长而且信息量比较大而已。它的意思是,这是个类型为 np.float32_t 的2维 np.ndarray。

    • 在函数体内部,我们一样可以使用 cdef typename varname 这样的语法来声明变量
    • 在 Python 程序中,是看不到 cdef 的函数的,所以我们这里 def naive_dot(a, b) 来调用 cdef 过的 _naive_dot 函数。

    另外,Cython 程序需要先编译之后才能被 Python 调用,流程是:

    1. Cython 编译器把 Cython 代码编译成调用了 Python 源码的 C/C++ 代码
    2. 把生成的代码编译成动态链接库
    3. Python 解释器载入动态链接库

    要完成前两步,我们要写如下代码:

    # setup.py
    from distutils.core import setup, Extension
    from Cython.Build import cythonize
    import numpy
    setup(ext_modules = cythonize(Extension(
        'dot_cython',
        sources=['dot_cython.pyx'],
        language='c',
        include_dirs=[numpy.get_include()],
        library_dirs=[],
        libraries=[],
        extra_compile_args=[],
        extra_link_args=[]
    )))
    

    这段代码对于我们这个简单的例子来说有些太复杂了,不过实际上,再复杂也就这么复杂了,为了省得后面再贴一遍,所以索性就在这里把最复杂的列出来好了。这里顺带解释一下好了:

    • 'dot_cython' 是我们要生成的动态链接库的名字
    • sources 里面可以包含 .pyx 文件,以及后面如果我们要调用 C/C++ 程序的话,还可以往里面加 .c / .cpp 文件
    • language 其实默认就是 c,如果要用 C++,就改成 c++ 就好了
    • include_dirs 这个就是传给 gcc 的 -I 参数
    • library_dirs 这个就是传给 gcc 的 -L 参数
    • libraries 这个就是传给 gcc 的 -l 参数
    • extra_compile_args 就是传给 gcc 的额外的编译参数,比方说你可以传一个 -std=c++11
    • extra_link_args 就是传给 gcc 的额外的链接参数(也就是生成动态链接库的时候用的)
    • 如果你从来没见过上面几个 gcc 参数,说明你暂时还没这些需求,等你遇到了你就懂了

    然后我们只需要执行下面命令就可以把 Cython 程序编译成动态链接库了。

    python setup.py build_ext --inplace
    

    成功运行完上面这句话,可以看到在当前目录多出来了 dot_cython.c 和 dot_cython.so。前者是生成的 C 程序,后者是编译好了的动态链接库。

    下面让我们来试试看效果:

    $ ipython                                                                                                   15:07:43
    Python 2.7.12 (default, Oct 11 2016, 05:20:59)
    Type "copyright", "credits" or "license" for more information.
    
    IPython 4.0.1 -- An enhanced Interactive Python.
    ?         -> Introduction and overview of IPython's features.
    %quickref -> Quick reference.
    help      -> Python's own help system.
    object?   -> Details about 'object', use 'object??' for extra details.
    
    In [1]: import numpy as np
    In [2]: import dot_python
    In [3]: import dot_cython
    In [4]: a = np.random.randn(100, 200).astype(np.float32)
    In [5]: b = np.random.randn(200, 50).astype(np.float32)
    
    In [6]: %timeit -n 100 -r 3 dot_python.naive_dot(a, b)
    100 loops, best of 3: 560 ms per loop
    
    In [7]: %timeit -n 100 -r 3 dot_cython.naive_dot(a, b)
    100 loops, best of 3: 982 µs per loop
    
    In [8]: %timeit -n 100 -r 3 np.dot(a, b)
    100 loops, best of 3: 49.2 µs per loop
    

    所以说,提升了大概 570 倍的效率!而我们的代码基本上就没有改动过!当然啦,你要跟高度优化过的 numpy 实现比,当然还是慢了很多啦。不过掐指一算,这 0.982ms 其实跟直接写 C++ 是差不多的,能实现这个这样的效果已经很令人满意了。不信我们可以试试看手写一次 C++ 版本:

    // dot.cpp
    #include <ctime>
    #include <cstdlib>
    #include <chrono>
    #include <iostream>
    
    class Matrix {
        float *data;
    public:
        size_t n, m;
        Matrix(size_t r, size_t c): data(new float[r*c]), n(r), m(c) {}
        ~Matrix() { delete[] data; }
        float& operator() (size_t x, size_t y) { return data[x*m+y]; }
        float operator() (size_t x, size_t y) const { return data[x*m+y]; }
    };
    
    float dot(const Matrix &a, const Matrix& b) {
        Matrix c(a.n, b.m);
        for (size_t i = 0; i < a.n; ++i)
            for (size_t j = 0; j < b.m; ++j) {
                float s = 0;
                for (size_t k = 0; k < a.m; ++k)
                    s += a(i, k) * b(k, j);
                c(i, j) = s;
            }
        return c(0, 0); // to comfort -O2 optimization
    }
    
    void fill_rand(Matrix &a) {
        for (size_t i = 0; i < a.n; ++i)
            for (size_t j = 0; j < a.m; ++j)
                a(i, j) = rand() / static_cast<float>(RAND_MAX) * 2 - 1;
    }
    
    int main() {
        srand((unsigned)time(NULL));
        const int n = 100, p = 200, m = 50, T = 100;
        Matrix a(n, p), b(p, m);
        fill_rand(a);
        fill_rand(b);
        auto st = std::chrono::system_clock::now();
        float s = 0;
        for (int i = 0; i < T; ++i) {
            s += dot(a, b);
        }
        auto ed = std::chrono::system_clock::now();
        std::chrono::duration<double> diff = ed-st;
        std::cerr << s << std::endl;
        std::cout << T << " loops. average " << diff.count() * 1e6 / T << "us" << std::endl;
    }
    
    $ g++ -O2 -std=c++11 -o dot dot.cpp
    $ ./dot 2>/dev/null
    100 loops. average 1112.11us
    

    可以看到相比起随手写的 C++ 程序,Cython 甚至还更快了些,或许是因为 numpy 以及计量方式(取3次最好 vs 取平均)的缘故。

    Cython 加速 Python 代码的关键

    如果我们把刚刚 Cython 代码中的类型标注都去掉(也就是函数参数和返回值类型以及函数体内部的 cdef),再试试看运行速度:

    $ python setup.py build_ext --inplace
    $ ipython
    In [1]: import numpy as np
    In [2]: import dot_python
    In [3]: import dot_cython
    In [4]: a = np.random.randn(100, 200).astype(np.float32)
    In [5]: b = np.random.randn(200, 50).astype(np.float32)
    
    In [6]: %timeit -n 100 -r 3 dot_cython.naive_dot(a, b)
    100 loops, best of 3: 416 ms per loop
    
    In [7]: %timeit -n 100 -r 3 dot_python.naive_dot(a, b)
    100 loops, best of 3: 537 ms per loop
    

    可以看到,这下 Cython 实现几乎和 Python 实现一样慢了。所以说,在 Cython 中,类型标注对于提升速度是至关重要的。

    到了这里就可以吐槽动态类型的不好了。单就性能方面来看,很多编译期间就能确定下来的事情被推到了运行时;很多编译期间能检查出来的问题被推到了运行时;很多编译期间能做的优化也被推到了运行时。再加上 CPython 又没有带 JIT 编译器,这相当于有相当大的时间都浪费在了类型相关的事情上,更不用说一大堆编译器优化都用不了。

    分析 Cython 程序

    前面说到,Cython 中类型声明非常重要,但是我们不加类型标注它依然是一个合法的 Cython 程序,所以自然而然地,我们会担心漏加类型声明。不过好在 Cython 提供了一个很好的工具,可以方便地检查 Cython 程序中哪里可能可以进一步优化。下面命令既可以对 dot_cython.pyx 进行分析:

    cython -a dot_cython.pyx
    

    如果当前 Cython 程序用到了 C++,那么还得加上 --cplus 参数。在成功运行完 cython -a 之后,会产生同名的 .html 文件。我们可以打开看看不带类型标注的版本:

    这里用黄色部分标出了和 Python 发生交互的地方,简单地理解,就是拖累性能的地方。点击每一行可以查看相应的生成的 C/C++ 代码。可以看到我们这里几乎每一行都被标了出来(汗……)

    这里我们点开了第16行,也就是 for k in xrange(p),可以发现这么一句简单的话,却被展开成了如此复杂的语句,从这一系列 Python API 的名称来看,我们至少额外地做了:创建和销毁 Python Object、增加和减少 Python Object 的引用计数、类型检查、列表长度检查等等……然而在不知道类型的情况下,为保证运行正确,这些事情又是不得不做的。

    我们把类型标注加回来,再看看 cython -a 的结果:

    这里同样展开了 for k in xrange(p) 这一行,可以看到,它很直接地就翻译成了 C 里面的 for 循环。其他地方同样也简化了很多,剩下的只有进出函数调用、raise ValueError 和 np.zeros 这些确实是要和 Python 发生交互的地方被标了出来。一般来说,我们把一个 Cython 程序优化到这个地步就行了。

    根据 Amdahl’s Law 我们知道(其实根据直觉我们也知道),只要最核心的代码足够快就行了。所以说,我们完全可以放心地编写 Python 代码,享受 Python 带来的好处,同时把核心代码用 C/C++ 或者 Cython 重写,这样就能兼顾开发效率和执行效率了。

    以上部分的参考资料:

    作为胶水

    Python 是很好的胶水语言,但是前提是库本身要使用 Python API 来和 Python 交互。有了 Cython 之后,我们可以照常编写 C/C++ 程序,或者是直接拿来一份已有的 C/C++ 源码,然后用 Cython 简单包装一下就可以使用了。

    本来我想胶水这一部分也像前面性能提升部分一样详细地写出来。后来想想,其实这一部分主要涉及的就是 Cython 语法本身,没有什么特别值得注意的,所以看看 Cython 文档就好了。我这里把一些特性不完全地列出来:

    • 函数签名基本上可以原样从 C/C++ 复制到 Cython 中
      • C 中的 _Bool 类型和 C++ 中的 bool 类型在 Cython 中都用 bint 取代(因为 Python 没有布尔类型)
    • struct / enum / union 是支持的
    • const 限定和引用都是支持的
    • 命名空间是支持的
    • C++ 类是支持的
    • 部分操作符重载是支持的,部分操作符需要改名
    • 内嵌类是支持的
    • 模板是支持的
    • 异常是支持的
    • 构造函数、析构函数是支持的
    • 静态成员是支持的
    • libc / libcpp / STL 是支持的
    • 声明写在 .pxd 中可以在 .pyx 中 cimport 进来
    • 你可能需要注意 Python 字符串到各式各样的 C/C++ 字符串的转换

    也就是说在 Cython 里面调用 C/C++ 代码应该是没有任何问题的,你想在 Cython 里面用 Python 的语法写 C/C++ 程序基本上也是没有问题的。具体的可以查阅以下资料:

    首发于博客 Python 多核并行计算

    转载自:https://zhuanlan.zhihu.com/p/24311879 陈乐群

     

     

     

     

     

    展开全文
  • Cython参考

    2017-10-19 16:39:25
    Cython的简单使用:http://www.cnblogs.com/freeweb/p/6548208.html编译Pipeline由于cython是python的超集,因此python解释器不能直接解释cython的代码,通过cython compilation pipeline,可以将cython代码转换为...
     

    Cython的简单使用:http://www.cnblogs.com/freeweb/p/6548208.html

    编译Pipeline

    由于cython是python的超集,因此python解释器不能直接解释cython的代码,通过cython compilation pipeline,可以将cython代码转换为python的扩展模块。pipeline分为

    两阶段:

    1. cython编译.pyx代码为c或c++文件.c、.cpp
    2. c/c++代码.c、.cpp编译成.so共享库

    标准编译路径

    python的标准库distutils package用来编译、打包、发布python项目,其中一个功能是将C代码编译成python的扩展模块。也就是编译pipeline中的第二个阶段。第一个阶段则交给cythonize命令。

    一个纯cython代码可以使用简单的setup.py脚本编译成为.so动态库,考虑以下cython代码(位置:/examples/02-compiling/distutils/fib.pyx):

    def fib(long n):
        '''Returns the nth Fibonacci number.'''
        cdef long a=0, b=1, i
        for i in range(n):
            a, b = a + b, a
        return a

    由于是纯cython代码,可以使用以下setup.py进行编译

    from distutils.core import setup
    from Cython.Build import cythonize
    #cythonize:编译源代码为C或C++,返回一个distutils Extension对象列表
    setup(ext_modules=cythonize('fib.pyx'))

    执行python setup.py build_ext -i

    在同一目录下,得到fib.c build/ 和扩展库fib.so,fib.so是可以通过from fib import fib进行调用的。

    使用cython包装纯c代码的编译

    在使用cython包装c代码时,编译时,需要指定额外的原文件,例如:

    cfib.c

    #include "cfib.h"
    
    unsigned long long fib(unsigned long n) {
        unsigned long a=0, b=1, i, tmp;
        for (i=0; i<n; ++i) {
            tmp = a; a = a + b; b = tmp;
        }
        return a;
    }

    wrap_fib.pyx

    cdef extern from "cfib.h":
        unsigned long _fib "fib"(unsigned long n)
    
    def fib(n):
        ''' Returns the nth Fibonacci number.'''
        return _fib(n)

    cfib.h略,在这种情况下,使用需要传递给cythonize的内容不能是wrap_fib.pyx,而是将wrap_fib.pyx与源文件cfib.c打包成一个Extension对象,setup.py如下:

    from distutils.core import setup, Extension
    from Cython.Build import cythonize
    
    # First create an Extension object with the appropriate name and sources
    ext = Extension(name="wrap_fib", sources=["cfib.c", "wrap_fib.pyx"])
    
    # Use cythonize on the extension object.
    setup(ext_modules=cythonize(ext))

    执行

    python setup.py build_ext -i

    得到wrap_fib.so

    如果cfib.c已经是预编译成动态库libfib.so,那么setup.py例子如下:

    from distutils.core import setup, Extension
    from Cython.Build import cythonize
    
    # First create an Extension object with the appropriate name and sources
    ext = Extension(name="wrap_fib", 
        sources=["wrap_fib.pyx"],
        library_dirs=["/path/libfib.so"],
        libraries=["fib"])
    
    # Use cythonize on the extension object.
    setup(ext_modules=cythonize(ext))

    IPython与Cython的动态编译(%%cython magic)

    Ipython的一个扩展功能是能够动态的编译cython代码为python扩展模块,打开这个功能,执行命令%load_ext cythonmagic,然后使用%%cython编写动态的cython代码,例子如下:

    %%cython
    def fib(int n):
        cdef int i
        cdef double a=0.0,b=1.0
        for i in range(n):
            a,b=a+b,a
        return a

    ipython将会把以上的代码在后台进行编译成.so然后导入当前的解释器,我们可以直接调用fib函数。

    %%cython 命令可以接受一些参数,--cplus c++代码,-I include,-c 编译参数。

    pyximport,import .pyx文件时进行编译

    pyximport可以在import一个pyx文件时动态对其进行编译,由于这种方法依赖于cython和gcc,因此不适合应用在生产系统上,例子:

    import pyximport
    #在import之前调用install命令
    pyximport.install()
    #import fib.pyx,和import fib.py的感觉一样
    import fib

    pyimport还能够处理更加复杂的情况,例如,可以处理cython文件中需要引用的别的c、c++头文件,还可以处理cython包含的其他cython文件。我们引入一个.pyxdeps文件来记录这些外部包含关系,将包含所有依赖文件的list,一行一个。pyxdeps文件只能处理代码的依赖性,如何将几个源代码编译和连接成一个python扩展模块,这还需要一个.pyxbld文件,.pyxbld文件中将包含一个或两个函数:

    make_ext(modname,pyxfilename)
        接受两个参数,返回一个Extension对象
    make_setup_args
        如果定义了,pyximport将额外的参数传递给setup函数

    例子(位置/examples/02-compiling/pyximport):

    _fic.c略
    _fib.h略
    fib.pyx

    #cfib函数包装了_fib.c中的_cfib函数
    cdef extern from "_fib.h":
        unsigned long int _cfib "fib"(unsigned long int)
    
    def cfib(unsigned long int n):
        return _cfib(n)
    #使用cython写的fib函数
    def fib(long n):
        '''Returns the nth Fibonacci number.'''
        cdef long a=0, b=1, i
        for i in range(n):
            a, b = a + b, a
        return a

    fib.pyxbld

    def make_ext(modname, pyxfilename):
        from distutils.extension import Extension
        return Extension(modname,
                #告诉distutils把哪些源文件link起来
                sources=[pyxfilename, '_fib.c'],
                #告诉distutils把在哪个路径查找头文件
                include_dirs = ['.'])
    
    # def make_setup_args():
        # return dict(script_args=["--compiler=mingw32"])

    执行pyximport就可以导入fib模块中的cfib和fib函数了

    手工编译cython

    这一节讨论如何手工编译cython代码,就以上一节的_fib.c,_fib.h,fib.pyx为例,fib.pyx中本身包含一个fib函数,同时包含一个包装_fib.c的函数cfib, 例子:

    #fib.pyx->fib.c
    cython fib.pyx
    #CLFAGS\LDFLAGS,编译连接参数
    CFLAGS=$(python-config --cflags)
    LDFLAGS=$(python-config --ldflags)
    #分别编译fib.c和_fib.c为fib.o和_fib.o
    gcc -c fib.c ${CFLAGS}
    gcc -c _fib.c ${CFLAGS}
    #连接
    gcc fib.o _fib.o -o fib.so -shared ${LDFLAGS}

    得到可调用的fib.so


    展开全文
  • Cython 3.0 中文文档 原文: 协议: 起初就把事情做对是完全没必要的。但最后要把事情做对是绝对必要的。——Andrew Hunt & David Thomas 下载 Docker docker pull apachecn0/cython-doc-zh docker run -tid -p ...
  • cython的瓶子 当需要进行必要的修改以使cython编译成字节码时,此repo将尝试保存的最新稳定版本。 当前版本0.12(稳定) ###编译 克隆此git clone git@github....
  • Welcome to Cython! Cython is a language that makes writing C extensions for Python as easy as Python itself. Cython is based on Pyrex, but supports more cutting edge functionality and optimizations. ...
  • 本节不具体讲解cython的原理和细节,提供一个最简单的例子,将一个python代码转化为一个cython代码,同时由于本人对cython刚入门,只会一个简单的操作,即在cython中声明变量的类型。实验证明,就这样简单添加变量...
  • learning cython programming

    2018-02-02 17:06:20
    learning cython programming, 融合c语言和python, 承担胶水
  • Cython初识

    2019-10-20 18:17:46
    1、cython简介 python作为一门强大的脚本语言,优势自然不必说。但是,当我们的模型较复杂,运算量较大的时候,python的短板就会出现,就是运算速度慢。当然,解决这一问题有很多方法,比如pypy的jit技术,但是...
  • Cython简介

    2020-10-25 11:14:45
    .pxd 文件类似于 C 语言的 .h 头文件,.pxd 文件中有 Cython 模块要包含的 Cython 声明 (或代码段)。 .pxd 文件可共享外部 C 语言声明,也能包含 C 编译器内联函数。.pxd 文件还可为 .pyx 文件模块提供 Cython ...
  • Cython安装

    2021-09-07 10:53:07
    Cython安装不上 今天安装环境的时候发现Cython==0.26.1安装不上 后来看了半天发现是和python版本不匹配 把python换成3.6.5 成功安装 特此记录
  • Cython 三分钟入门教程

    2020-12-25 09:46:00
    Cython 试图消除这种两重性,并让你同时拥有 Python 的语法和 C 数据类型和函数——它们两个都是世界上最好的。请记住,我绝不是我在这方面的专家,这是我的第一次Cython真实体验的笔记: 编辑:根据一些我收到的...
  • 程序员常刷题Cython 与 SWIG,战斗! 作者: 马克·科勒 日期: 2013-03-16 为 Python 包装 C 库 您好,欢迎来到 Cython vs SWIG,战斗! 这个演讲是关于当你意识到并非所有东西都在标准库中时会发生什么。 事实上,...
  • Cython基础--Cython入门

    千次阅读 2017-03-25 09:35:39
    Cython入门 1 Cython是什么? 对你没有看错,是Cython,不是Python当初也我也对这个名字感到很奇怪,但是了解之后,再才知这是我一直想要的工具,比起swig,这个工具要好上很多它是一个用来快速生成Python扩展模块...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,871
精华内容 6,748
关键字:

cython