首页 > 其他分享 >cython简单入门

cython简单入门

时间:2023-11-29 16:56:41浏览次数:48  
标签:cython cdef 入门 int py 简单 np MyDemo

cython

Cython是一个编程语言,它通过类似Python的语法来编写C扩展并可以被Python调用.既具备了Python快速开发的特点,又可以让代码运行起来像C一样快,同时还可以方便地调用C library。

1. 环境配置

1.1 windows

安装MingW-w64编译器:conda install libpython m2w64-toolchain -c msys2
在Python安装路径下找到\Lib\distutils文件夹,创建distutils.cfg写入如下内容:
[build] compiler=mingw32

1.2 macOS

安装XCode

1.3 linux

sudo apt-get install build-essential

1.4 安装cython

  • pip install cython
  • conda install cython

2. 例子:矩阵乘法

2.1 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

2.2 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)

2.3 差异点

  • Cython 程序的扩展名是 .pyx

  • cimport 是 Cython 中用来引入 .pxd 文件的命令,可以简单理解成 C/C++ 中用来写声明的头文件

  • @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
    
  • 在函数体内部,我们一样可以使用 cdef typename varname 这样的语法来声明变量

  • 在 Python 程序中,是看不到 cdef 的函数的,所以我们这里 def naive_dot(a, b) 来调用 cdef 过的 _naive_dot 函数

2.4 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 程序,后者是编译好了的动态链接库。

3. 例子:求质数

prime.pyx

# distutils: language=c++

from libcpp.vector cimport vector

def prime_py(number):
    plist = []
    for n in range(2, number + 1):
        for x in range(2, n):
            if n % x == 0:
                break
        else:
            plist.append(n)

    return plist



def prime_cy(int number):
    cdef int x, n
    cdef vector[int] plist
    


    for n in range(2, number + 1):
        for x in range(2, n):
            if n % x == 0:
                break
        else:
            plist.push_back(n)

    return plist

setup.py

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules=cythonize("prime.pyx")
)

准备

python setup.py build_ext --inplace

test_prime.py

import prime
import time


cy_start = time.time()
prime.prime_cy(50000)
cy_end = time.time()
print('cython : ',cy_end - cy_start)


py_start = time.time()
prime.prime_py(50000)
py_end = time.time()
print('python : ',py_end - py_start)

4. 例子: 从 c++ 里导入函数

demo.h

#ifndef DEMO_H
#define DEMO_H 
using namespace std;
namespace demo {
    class MyDemo {
        public:
            int a;
            MyDemo();
            MyDemo(int a );
            ~MyDemo(); 
            int mul(int m );
            int add(int b);
            void sayHello(char* name);
    };
}

int func(int x){
return x * 10;
}
#endif

demo.cpp

#include "demo.h" 
#include <iostream> 

namespace demo {
 
    MyDemo::MyDemo () {}
 
    MyDemo::MyDemo (int a) {
        this->a = a; 
    }
 
    MyDemo::~MyDemo () {}
 
    int MyDemo::mul(int m) {
        return this->a*m;
    }
 
    int MyDemo::add (int b) {
        return this->a+b;
    }
    void MyDemo::sayHello(char* name){
        cout<<"hello "<<name<<"!"<<endl;
    }

   
}

cdemo.pyd

  • pyd连接c++和pyx
cdef extern from "demo.cpp":
    pass

# Decalre the class with cdef
cdef extern from "demo.h" namespace "demo":
    cdef cppclass MyDemo:
        MyDemo() except +
        MyDemo(int) except +
        int a
        int mul(int )
        int add(int )
        void sayHello(char*)
        
cdef extern from "demo.h":
    int func(int )

cpyep.pyx

  • pyx 连接 pyd 和 python
# distutils: language = c++

from cdemo cimport MyDemo


# Create a Cython extension type which holds a C++ instance
# as an attribute and create a bunch of forwarding methods
# Python extension type.
cdef class PyMyDemo:
    cdef MyDemo c_mydemo  # Hold a C++ instance which we're wrapping

    def __cinit__(self,a):
        self.c_mydemo = MyDemo(a)   
    def mul(self, m):
        return self.c_mydemo.mul(m)

    def add(self,b):
        return self.c_mydemo.add(b)

    def sayHello(self,name ):
        self.c_mydemo.sayHello(name) 
        
from cdemo cimport func
def funcc(int x):  
    return func(x)

setup.py

  • 生成动态库
  • python setup.py build_ext --inplace
from setuptools import setup 

from Cython.Build import cythonize

setup(ext_modules=cythonize("cpyep.pyx"))

test.py

from cpyep import *
print(funcc(10))
# output : 100

一些注意点

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

标签:cython,cdef,入门,int,py,简单,np,MyDemo
From: https://www.cnblogs.com/InsiApple/p/17865276.html

相关文章

  • Istio从入门到精通—— 流量治理的原理 —— 故障注入
     流量治理的原理——故障注入一、故障注入的概念 流量治理的原理中的故障注入是一种重要的技术手段,用于评估和提升系统的可靠性。其基本原理是在系统正常运行时,人为地引入一些故障,以测试系统的健壮性和容错能力。通过这种方式,我们可以发现并解决系统中可能存在的问题,从而确......
  • 通过Java-Netty实现一个简单的HTML实时聊天——demo
    demo效果初步准备想要实现聊天就需要用到WebSocket,他是专门用于http进行实时聊天的的协议。因为主要核心在后端开发,所以我去白嫖了个超级简单的界面(就是不会!)我编写demo时系统环境为Win-11,Java-8环境依赖只需要一个netty即可实现需要的功能<!--netty--><dependency><g......
  • 入门Windows驱动程序
    来自:https://www.anquanke.com/post/id/85972入门Windows驱动程序:0x1 背景笔者在学习中发现,关于Windows驱动编程的文章多不胜数,但是其中很多文章的内容繁杂不便于了解与学习,缺少对内容精准的概括与总结,所以本篇文章将对Windows驱动编程进行一次总结性介绍。文章将分为两个部......
  • 即时通讯技术文集(第25期):实时音视频基础入门 [共20篇]
    ​为了更好地分类阅读52im.net总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第25 期。[- 1 -] 即时通讯音视频开发(一):视频编解码之理论概述[链接] http://www.52im.net/thread-228-1-1.html[摘要] 本文主要讲解实时音视频技术中视频技术的编解码基础理......
  • kore 配置简单说明
    kore官方提供对于配置的说明比较少(只包含了一些核心的,其他的没有详细说明)但是提供了一个参考示例一些配置实际建议还是通过结合代码阅读比较方便,config.c中关于配置有比较完整的说明,同时也会发现一些官方暂时没介绍的http_server_version配置这个是配置serverresponse......
  • 神经网络入门篇之深层神经网络:详解前向传播和反向传播(Forward and backward propagati
    深层神经网络(DeepL-layerneuralnetwork)复习下前面的内容:1.逻辑回归,结构如下图左边。一个隐藏层的神经网络,结构下图右边:注意,神经网络的层数是这么定义的:从左到右,由0开始定义,比如上边右图,\({x}_{1}\)、\({x}_{2}\)、\({x}_{3}\),这层是第0层,这层左边的隐藏层是第1层,由此类推......
  • SpringMVC_2023_11_27_2 SpringMVC_入门(注解形式)
    SpringMVC_入门---(注解形式)2023-11-2816:31:09星期二常用的注解:@Controller:标注当前类为:处理器@RequestMapping:设置请求链接SpringMVC注解项目的搭建a) 依赖的引入<dependencies><dependency><groupId>javax.servlet</groupId><......
  • 汇编--简单的子程序调用
    目录前言程序要求思路十进制转二进制二进制转十六进制代码实现数据段定义十进制转二进制子程序运行结果二进制转十六进制子程序运行结果main程序前言本文将以十进制转二进制以及二进制转十进制为例,展示汇编子程序的基本语法。程序要求使用两个子程序,定义一个变量a=156,一个8......
  • JFinal框架入门版本
    项目结构具体代码//DemoConfig.javapackagecom.demo.config;importcom.demo.controller.HelloController;importcom.jfinal.config.*;importcom.jfinal.template.Engine;publicclassDemoConfigextendsJFinalConfig{@OverridepublicvoidconfigConst......
  • LuCI2开发入门指南
    LuCI2开发入门指南来源 https://www.openwrt.pro/post-558.html参考 https://iyzm.net/openwrt/624.html LUCI界面OpenWrt的界面其实就是网页界面,默认是由uhttpd服务器承载,之所以叫做 LUCI,因为这是使用Lua 脚本编写的控制界面,全称LuaUnifiedConfigurationInt......