网络编程
位置:首页>> 网络编程>> Python编程>> 如何用C代码给Python写扩展库(Cython)

如何用C代码给Python写扩展库(Cython)

作者:jazz_bin  发布时间:2023-06-08 17:06:32 

标签:C代码,Python,扩展库,Cython

之前一篇文章里提到了利用Cython来编译Python,这次来讲一下如何用Cython给Python写扩展库。

两种语言混合编程,其中最重要的是类型的传递。

我们用一个简单的例子进行入门:这次的目标是用C语言写一个Numpy的加法和元素相乘模块。在本例中,Numpy的array被传入到C语言模块内,变成了二维数组。

1. 头文件main.h:


#ifndef _MAIN_H
#define _MAIN_H
void plus(double *a, double *b, double *r, int n, int m); // 矩阵加法
void mul(double *a, double *b, double *r, int n, int m); // 矩阵按元素相乘
void main(double *a, double *b, double *r, int n, int m, int times); // 用于测试的main函数
#endif

2.  把主要代码写在main.c中:


#include "main.h"

/***********************************
* 矩阵的加法
* 利用数组是顺序存储的特性, *
* 通过降维来访问二维数组! *
* r
***********************************/
void plus(double *a, double *b, double *r, int n, int m)
{
 int i, j;
 for(i = 0; i < n; i++)
 {
   for(j = 0; j < m; j++)
     *(r + i*m + j) = *(a + i*m + j) + *(b + i*m + j);
 }
}

/***********************************
* 矩阵的按元素乘法
* 利用数组是顺序存储的特性, *
* 通过降维来访问二维数组! *
* r
***********************************/
void mul(double *a, double *b, double *r, int n, int m)
{
 int i, j;
 for(i = 0; i < n; i++)
 {
   for(j = 0; j < m; j++)
     *(r + i*m + j) = *(a + i*m + j) * *(b + i*m + j);
 }
}

/***********************************
* main函数
* 利用数组是顺序存储的特性, *
* 通过降维来访问二维数组! *
* r
***********************************/
void main(double *a, double *b, double *r, int n, int m, int times)
{
 int i;
 // 循环times次
#pragma omp parallel for
 for (i = 0; i < times; i++)
 {
   // 矩阵的加法
   plus(a, b, r, n, m);

// 矩阵按元素相乘
   mul(a, b, r, n, m);
 }
}

这个main.c中实现了矩阵的加法、矩阵按元素相乘的功能,用到的数据结构是二维数组,但是因为C语言中给函数传递二维数组比较麻烦,这里用降维的方法实现。另外在main()函数中,采用一个循环来进行测试,以测试性能。

3. 下面编写test.pyx文件来调用上述C函数(注意,后缀是.pyx噢):详细的知识点在注释中写出来了~


# 既要import numpy, 也要用cimport numpy
import time
import numpy as np
cimport numpy as np

# 使用Numpy-C-API
np.import_array()

# cdefine C 函数
cdef extern from "main.h":
 void plus(double *a, double *b, double *r, int n, int m)
 void mul(double *a, double *b, double *r, int n, int m)
 void main(double *a, double *b, double *r, int n, int m, int times)

"""
# 定义一个"包装函数", 用于调用C语言的main函数,调用范例:plus_fun(a, b, r)
# 在这里要注意函数传入的参数的类型声明,double表示数组的元素是double类型的,
# ndim = 2表示数组的维度是2
# 在调用main函数时,要把python的变量强制转化成相应的类型(以确保无误),比如<int>
# 当然,基本类型如int,可以不显式地写出来,如下面的a.shape[0]、a.shape[1]
"""
def main_func(np.ndarray[double, ndim=2, mode="c"] a not None,
          np.ndarray[double, ndim=2, mode="c"] b not None,
          np.ndarray[double, ndim=2, mode="c"] r not None,
          times not None):
 main(<double*> np.PyArray_DATA(a),
       <double*> np.PyArray_DATA(b),
       <double*> np.PyArray_DATA(r),
       a.shape[0],
       a.shape[1],
       <int> times)

4. 为了用Cython编译上述代码,我们创建一个setup.py文件:


import numpy
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

filename = 'test' # 源文件名
full_filename = 'test.pyx' # 包含后缀的源文件名

setup(
 name = 'test',
 cmdclass = {'build_ext': build_ext},
 ext_modules=[Extension(filename,sources=[full_filename, "main.c"],
        include_dirs=[numpy.get_include()])],
)

5. 上述的main.h、main.c、test.pyx一定要放在同一个文件夹下。此时在该文件夹下按住shift键,然后右击鼠标,打开cmd或PowerShell控制台,在控制台中运行以下命令进行Cython编译:

python setup.py build_ext --i

或者:

python setup.py build_ext --inplace

编译成功的图例:

如何用C代码给Python写扩展库(Cython)

此时在同目录下会生成“test.cp36-win_amd64.pyd”的二进制码文件,它是闭源的,但是可以直接用python来import。下面编写测试代码main.py来进行测试:


import test
import time
import numpy as np

start_time = time.time()
a = np.random.rand(100, 100) * 2 - 1 # 生成300*300的随即矩阵
b = np.random.rand(100, 100) * 2 - 1
r = np.empty_like(a) # 创建一个空矩阵,用来存储计算结果
test.main_func(a, b, r, 500000) # 调用main_func进行测试
end_time = time.time()
print(end_time - start_time) # 输出时间
print(r) # 输出运行结果

执行结果:

如何用C代码给Python写扩展库(Cython)

通过本例我们可以看到:将循环放在C语言模块中,而不是原生的Python中,可以提高执行效率。

来源:https://blog.csdn.net/qq_33353186/article/details/80298239

0
投稿

猜你喜欢

  • 说明:本文内容都是从Google上搜索来的,本想上http://www.alexa.com/查官方数据,访问非常慢暂且没查。使用本接口将返回
  • python 读取语音文件时,常用的无非以下三种方式,但是在我们数据量变的很大是,不同的读取方式之间的性能差异就会被进一步放大,于是本文着重
  • 就是一个简单的python查询百度关键词排名的函数,以下是一些简介:1、UA随机2、操作简单方便,直接getRank(关键词,域名)就可以了
  • PHP xpath() 函数定义和用法xpath()函数运行对 XML 文档的 XPath 查询。如果成功,该函数返回 SimpleXMLE
  • 一、创建生成器通过列表⽣成式,我们可以直接创建⼀个列表。但是,受到内存限制,列表容量肯定是有限的。⽽且,创建⼀个包含100万个元素的列表,不
  • 让我们看看如何在 Python 中复制数组。 有 3 种复制数组的方法:只需使用赋值运算符。浅拷贝深拷贝1 使用赋值运算符我们可以使用赋值运
  • 安装使用pip install XlsxWriter来安装,Xlsxwriter用来创建excel表格,功能很强大,下面具体介绍:1.简单使
  • 本文实例讲述了python中sleep函数用法。分享给大家供大家参考。具体如下:Python中的sleep用来暂停线程执行,单位为秒#---
  • 如何实现刷新当前页面呢?借助js你将无所不能。1,reload 方法,该方法强迫浏览器刷新当前页面。语法:location.reload([
  • 在看到7yue博客——“换手来用”的思考 有这么一句话:RIA是一个更趋向于“体验”设计的领域,不仅仅包括“开发人员”,还包括“设计人员”,
  • 这是由十几位视觉设计师设计的挂历,每个月份都是不同的风格,就像每个月都有不同温度和心情一样,思维跳跃性很大,可以作为挂历设计参考。当然,如果
  • 公司客户在使用网站后台编辑添加修改内容时,经常是直接从word文档里复制内容到编辑器里后就提交。结果是在内容显示页面上是五花八门的样式,有时
  • 英文原文:http://www.456bereastreet.com/archive/200601/css_3_selectors_expl
  • 如果是感应触发.就选onmouseover如果是点击触发.就选onclick    [把它们两互相替换,就可随时变为感应
  • 在python中经常会用到pandas来处理数据,最常用的数据类型是dataframe,但是有时候在dataframe有时间字段需要画时间序
  • 本文实例讲述了python字典序问题,分享给大家供大家参考。具体如下:问题描述:将字母从左向右的次序与字母表中的次序相同,且每个字符最大出现
  • 其实想实现这种功能很简单,首先要上传一个RAR的解压程序,就是RAR自己的解压程序,只需要它的核心程序RAR.EXE这个文件就可以了。然后就
  • 如果你有一字段dm记录了一个url,为了更好的优化模糊查询速度或统计速度,在数据表原有的结构上增加3个字段,分别为  `sdm`
  • 1、什么是AspJpeg?AspJpeg是一款功能强大的基于Microsoft IIS环境的图片处理组件,网络上对其进行详细和深入介绍的中文
  •  代码如下:using System; using System.Data; using System.Configuration
手机版 网络编程 asp之家 www.aspxhome.com