首页 > 其他分享 >Cython与C函数的结合

Cython与C函数的结合

时间:2024-07-25 15:22:08浏览次数:7  
标签:Cython arr 函数 Python sum C语言 结合 np

技术背景

在前面一篇博客中,我们介绍了使用Cython加速谐振势计算的方法。有了Cython对于计算过程更加灵活的配置(本质上是时间占用和空间占用的一种均衡),及其接近于C的性能,并且还最大程度上的保留了Python的编程语法特点,因此Cython确实是值得Python编程爱好者学习的一种加速手段。这里我们要介绍的是Cython与C语言相结合的一种方案,可以直接在pyx文件中加载C语言代码。

测试场景

我们测一个非常简单的场景————归约求和:

\[S=\sum_{i,j}A_{i,j} \]

当然了,像这种基本运算,在Numpy中已经优化的非常极致了。所以,这里我们并不是要展现Cython在性能上的优势,而是Cython对于C语言和Python语言两者的兼容性。首先我们用C语言实现一个归约求和的简单函数:

// array_sum.c
double reduce_sum(int arr_len, double* arr){
    double s=0.0;
    int i;
    for (i=0; i<arr_len; i++){
        s = s + *arr;
        arr++;
    }
    return s;
}

这里我们使用了一个指针数组,然后用for循环进行遍历计算。在Cython中,我们可以使用extern来直接加载C语言中的这个函数:

# test_pointer.pyx
import numpy as np
cimport numpy as np

cdef extern from "array_sum.c":
    double reduce_sum(int arr_len, double* arr)

cpdef rsum(int arr_len, np.ndarray[np.float64_t, ndim=2, mode="c"] arr):
    cdef:
        double* arr_ptr = <double *>arr.data
        double res = 0.0
    res = reduce_sum(arr_len, arr_ptr)
    return res

这里加载了C语言中的reduce_sum函数,然后以Cython中定义的rsum函数作为一个接口,将传入的numpy数组的内存地址作为指针传给C语言中写好的函数。然后需要对这个pyx文件进行编译构建:

$ cythonize -i test_pointer.pyx

编译完成后会在当前路径下生成*.c文件和*.so文件:

$ ll | grep test_pointer  
-rw-r--r-- 1 root root  374450 Jul 25 14:52 test_pointer.c
-rwxr-xr-x 1 root root  234848 Jul 25 14:52 test_pointer.cpython-37m-x86_64-linux-gnu.so*
-rw-r--r-- 1 root root     347 Jul 25 15:02 test_pointer.pyx

调用Cython函数

我们可以开启一个Ipython,或者直接在Python脚本文件中调用Cython函数:

In [1]: import numpy as np

In [2]: from test_pointer import rsum

In [3]: num=10000

In [4]: x=np.random.random((num,num))

In [5]: x.shape
Out[5]: (10000, 10000)

In [6]: %timeit s=np.sum(x)
38.3 ms ± 254 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [7]: %timeit rs=rsum(num*num,x)
51.7 ms ± 302 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [15]: np.sum(x)
Out[15]: 50003980.32921535

In [17]: rsum(num*num, x)
Out[17]: 50003980.32921728

经过测试,确实可以在Python中调用这个C语言实现的函数。当然,前面也提到过,Numpy对于这个简单的求和计算已经优化的非常好了,所以这里没有体现出性能上的优势,这里更多的是演示一个方法。

总结概要

这篇文章介绍了Python-Cython-C三种语言的简单耦合,以Cython为中间接口,实现Python数据传到C语言的后端执行相关计算。这就相当于可以在Python中调用C语言中的指针功能来进行跨维度的数组运算,至于性能依然存在优化空间,这里仅仅做一个简单的功能演示。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/cython-c.html

作者ID:DechinPhy

更多原著文章:https://www.cnblogs.com/dechinphy/

请博主喝咖啡:https://www.cnblogs.com/dechinphy/gallery/image/379634.html

标签:Cython,arr,函数,Python,sum,C语言,结合,np
From: https://www.cnblogs.com/dechinphy/p/18323048/cython-c

相关文章

  • C++(构造函数参数列表初始化)
    目录1.构造函数参数列表初始化的语法2.为什么使用参数列表初始化3.示例4.常量和引用成员的示例5.使用参数列表初始化的注意事项6.总结在C++中,构造函数参数列表初始化(initializerlist)是一种用于在对象创建时初始化成员变量的语法。这种方式在性能和可读性方面具有一些优势,......
  • 【学习笔记】构造函数、原型对象、原型链
    在JavaScript中,每个对象都有一个原型对象,原型对象也是一个对象,它包含了对象的共享属性和方法。每个构造函数(除了箭头函数)都有一个prototype属性,该属性指向构造函数的原型对象。当我们使用构造函数创建一个新对象时,该对象会继承构造函数的原型对象中的属性和方法,这种继承关系......
  • STL 容器以及各函数及其复杂度
    主要是实质、函数、性质。如果没有特殊提出,那么是常数复杂度。vector相当于变长数组。支持随机访问(可以直接查询\(v_i\)),但是不任意位置\(O(1)\)插入。通常为了保证效率,只在末尾加入删除元素。size:返回实际长度(通常声明的长度会大于实际长度),也就是包含的元素个数。empty:......
  • Java8 函数式编程和Lambda
    lambda初识lambda表达式一个简单的方法,比较两个Integer:publicvoidTest1(){ Comparator<Integer>com=newComparator<Integer>(){ @Override publicintcompare(Integero1,Integero2){ returnInteger.compare(o1,o2); } }; TreeSet<Integer>......
  • Mysql 函数 (进阶介绍 八)
    目录MySQLCURTIME()函数定义和用法语法实例MySQLDATE()函数定义和用法语法实例MySQLEXTRACT()函数定义和用法语法实例MySQL字符串连接CONCAT()函数使用方法:MySQL字符串截取SUBSTRING()函数 使用方法:MySQL数学函数使用方法:mysqlsubstr()函数截......
  • Qt基础 | Qt SQL模块介绍 | Qt SQL模块常用类及其常用函数介绍
    文章目录一、QtSQL模块概述1.Qtsql支持的数据库2.SQLite数据库3.QtSQL模块的主要类一、QtSQL模块概述  QtSQL模块提供数据库编程的支持,Qt支持多种常见的数据库,如MySQL、Oracle、MSSQLServer、SQLite等。QtSQL模块包括多个类,可以实现数据库连接、SQ......
  • 错误 1 error LNK2019: 无法解析的外部符号 _MQTTClient_create,该符号在函数 "protect
    前言全局说明错误1errorLNK2019:无法解析的外部符号_MQTTClient_create,该符号在函数"protected:virtualint__thiscallCmfc_mqttclientpoweronoffDlg::OnInitDialog(void)"(?OnInitDialog@Cmfc_mqttclientpoweronoffDlg@@MAEHXZ)中被引用一、说明环境:Windows1......
  • C++深拷贝构造函数解决浅拷贝的堆区内存重复释放问题
    1.简单介绍先简单介绍一下浅拷贝和深拷贝:浅拷贝->简单的赋值拷贝操作,默认的拷贝构造函数就是浅拷贝。深拷贝->在堆区重新申请空间,进行拷贝操作。2.问题展示下面用代码示例明了地展示默认拷贝构造函数浅拷贝带来地堆区内存重复释放问题:#include<iostream>usingnamespace......
  • 为什么上传文件时我的 Azure 函数应用 blob 触发器不起作用?
    我用python创建了一个blob触发函数应用程序。我的存储帐户中还有一个Blob存储。设置(local.settings,function.json)似乎没问题。运行:funcstart并在blob中上传文件后,没有任何反应。这是代码:importloggingfromazure.functionsimportInputStreamimportpand......
  • 字符串的相关案例和string库函数的使用
    字符串的存储特性:在存储过程中字符串都会在末尾自动添加一个结尾标志符\0                 来表示字符串结束字符串的定义方式有两种:方式一:利用字符数组+双引号的方式定义字符串例如:charstr[4]=“abc”;注意:这里的数组长度要么......