Python中使用C扩展详解
文章目录
- 1. Python/C API
- 示例
- 2. Cython
- 示例
- 3. ctypes
- 关于C扩展的进一步讨论
- 安全性和兼容性
- 性能优化策略
- 调试C扩展
- 发布和分发C扩展
- 应用实例:加速矩阵乘法运算
- 1. 准备C扩展代码
- 2. 编译C扩展
- 3. 在Python中使用C扩展
在Python中,使用C扩展是一种提高程序性能、访问底层系统资源或复用现有C代码的方法。Python提供了几个库和工具来帮助开发者编写、编译和加载C扩展模块,最常用的有
Python/C API
、
Cython
和
ctypes
。
1. Python/C API
Python/C API允许你直接用C语言编写Python模块。这意味着你可以创建新的数据类型、定义函数,并直接与Python解释器交互。使用API的一般步骤包括:
- 编写C代码实现功能。
- 使用API定义Python类型的对象和方法。
- 编译C代码为共享库(
.so
文件)。 - 在Python中通过
import
语句加载这个库。
示例
一个简单的C扩展模块示例,该模块提供一个函数计算两个整数的和:
// example.c
#include <Python.h>static PyObject* example_add(PyObject* self, PyObject* args) {int a, b;if (!PyArg_ParseTuple(args, "ii", &a, &b)) {return NULL;}return Py_BuildValue("i", a + b);
}static PyMethodDef ExampleMethods[] = {{"add", (PyCFunction)example_add, METH_VARARGS, "Add two numbers"},{NULL, NULL, 0, NULL}
};static struct PyModuleDef examplemodule = {PyModuleDef_HEAD_INIT,"example", /* name of module */NULL, /* module documentation, may be NULL */-1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ExampleMethods
};PyMODINIT_FUNC PyInit_example(void) {return PyModule_Create(&examplemodule);
}
编译此代码需要使用Python的开发头文件和库,通常命令如下(假设已安装Python开发包):
gcc -shared -o example.so -I/usr/include/python3.x example.c -lpython3.x
然后在Python中导入这个模块:
import example
print(example.add(1, 2))
2. Cython
Cython是一个更高级的工具,它允许你用类似Python的语法编写代码,然后将其编译成C扩展。Cython添加了静态类型声明,从而能够更高效地调用C库和执行操作。使用Cython,通常涉及以下步骤:
- 安装Cython。
- 编写
.pyx
文件,其中可以混合Python和C类型的注解。 - 使用Cython编译器生成C代码。
- 编译生成的C代码到共享库。
- 在Python中导入这个库。
示例
Cython版本的上述示例:
# example.pyx
def add(int a, int b):return a + b
使用Cython编译并使用这个模块,首先安装Cython(如果尚未安装):
pip install cython
然后编译example.pyx
文件:
cythonize -3 -i example.pyx
这将生成一个可以直接在Python中导入的共享库文件。之后在Python中使用:
import example
print(example.add(1, 2))
3. ctypes
ctypes
是Python标准库的一部分,它提供了一个更灵活但可能更复杂的途径来调用C库中的函数,而不需要预先编译C代码。你直接在Python中定义C数据类型和函数原型,然后加载动态链接库。
选择哪种方式取决于你的具体需求:如果追求极致性能且不介意更复杂的开发流程,直接使用Python/C API
或Cython
可能是最佳选择;如果你只是想简单地调用现有的C库函数,ctypes
可能更合适。每种方法都有其优势和适用场景,关键在于权衡开发效率、维护成本和性能需求。
关于C扩展的进一步讨论
安全性和兼容性
- 安全性:直接使用C扩展时,需要格外小心内存管理和其他潜在的错误,因为C语言不会自动处理这些错误,而Python则设计得更为健壮。使用Cython可以在一定程度上减少这类问题,因为它提供了更多的错误检查。
- 兼容性:C扩展通常需要针对特定的Python版本编译。这意味着如果你的扩展需要在不同Python版本上运行,可能需要为每个版本分别编译。Cython和Python/C API都提供了宏和条件编译功能来帮助处理兼容性问题。
性能优化策略
- 减少Python/C切换开销:在编写C扩展时,尽量减少从Python环境到C环境的转换次数。例如,在循环中避免频繁调用Python API。
- 使用缓冲区协议:对于大量数据处理,利用Python的缓冲区协议(buffer protocol)可以更高效地处理数组和缓冲区数据,避免复制。
- 多线程和异步:虽然C扩展可以直接使用多线程,但需要注意全局解释器锁(GIL)。对于CPU密集型任务,考虑使用子进程或者结合Python的异步IO功能。
调试C扩展
调试C扩展比调试纯Python代码要复杂一些,但也有相应的工具可用:
- gdb:GNU调试器,可以用来调试C代码。当你的扩展崩溃或行为异常时,gdb可以帮助定位问题。
- Cython调试:如果使用Cython,可以在编译时开启调试信息,然后使用gdb或IDE的调试功能。
- Python的
faulthandler
模块:可以在Python程序崩溃时输出堆栈跟踪,帮助识别问题所在。
发布和分发C扩展
- 预编译二进制包:为了便于用户安装,可以为常见的操作系统和Python版本预编译二进制包。
- 使用CMake或Setuptools:这些工具可以帮助自动化编译过程,使得安装过程对用户更加友好。特别是
Setuptools
的Extension
类可以用来指定C扩展的编译选项,并自动构建。
C扩展是提升Python应用性能的有效手段,尤其是在处理高性能计算、密集运算或硬件交互等场景。正确使用这些技术,结合良好的编程实践和调试技巧,可以极大地增强Python应用的能力。不过,由于其增加了开发和维护的复杂度,因此在决定是否采用C扩展前,应当仔细评估性能提升与额外工作量之间的平衡。
应用实例:加速矩阵乘法运算
假设我们有一个应用场景,需要频繁进行大规模矩阵乘法运算,而Python原生的矩阵乘法可能无法满足性能要求。这时,通过编写C扩展来加速这一过程是一个不错的选择。这里以使用Python/C API
为例,展示如何实现这一优化。
1. 准备C扩展代码
首先,我们编写C代码来实现矩阵乘法。这个C函数将接收两个二维数组(矩阵),计算它们的乘积,并返回结果矩阵。
// matrix_multiply.c
#include <Python.h>void matmul(int n, double* A, double* B, double* C) {for(int i = 0; i < n; ++i) {for(int j = 0; j < n; ++j) {double sum = 0;for(int k = 0; k < n; ++k) {sum += A[i*n+k] * B[k*n+j];}C[i*n+j] = sum;}}
}static PyObject* py_matrix_multiply(PyObject* self, PyObject* args) {int n;PyObject* py_A, *py_B;double* A, *B, *C;// 解析输入参数if (!PyArg_ParseTuple(args, "O!O!i", &PyArray_Type, &py_A, &PyArray_Type, &py_B, &n)) {return NULL;}// 确保输入是二维数组且元素类型为doubleif (PyArray_NDIM(py_A) != 2 || PyArray_NDIM(py_B) != 2 ||PyArray_TYPE((PyObject*)py_A) != NPY_DOUBLE ||PyArray_TYPE((PyObject*)py_B) != NPY_DOUBLE) {PyErr_SetString(PyExc_TypeError, "Input arrays must be 2D and of type double.");return NULL;}// 获取数据指针A = (double*)PyArray_DATA(py_A);B = (double*)PyArray_DATA(py_B);C = (double*)malloc(n*n*sizeof(double));// 执行矩阵乘法matmul(n, A, B, C);// 创建并返回结果numpy数组PyObject* result = PyArray_SimpleNewFromData(2, &n, NPY_DOUBLE, (void*)C);Py_INCREF(result); // 增加引用计数,防止数据被提前释放return result;
}static PyMethodDef MatrixMethods[] = {{"matrix_multiply", py_matrix_multiply, METH_VARARGS, "Multiply two matrices."},{NULL, NULL, 0, NULL}
};// 模块初始化
static struct PyModuleDef matrix_module = {PyModuleDef_HEAD_INIT,"matrix_extension",NULL,-1,MatrixMethods
};PyMODINIT_FUNC PyInit_matrix_extension(void) {import_array(); // 初始化numpy C APIreturn PyModule_Create(&matrix_module);
}
2. 编译C扩展
确保已经安装了NumPy以及Python的开发包,然后使用如下命令编译C扩展:
gcc -shared -o matrix_extension.so -I/usr/include/python3.x -lpython3.x matrix_multiply.c -lpython3.x -lm
请根据你的Python版本和路径调整上述命令。
3. 在Python中使用C扩展
接下来,在Python脚本中导入并使用这个C扩展来加速矩阵乘法运算。
import numpy as np
import matrix_extension# 创建两个随机矩阵
n = 1000
A = np.random.rand(n, n)
B = np.random.rand(n, n)# 使用C扩展进行矩阵乘法
C = matrix_extension.matrix_multiply(A, B, n)print("Resulting matrix shape:", C.shape)
通过这种方式,我们利用C语言的直接内存访问和控制能力,绕过了Python解释器的层次,实现了高效的矩阵乘法运算,显著提高了执行速度。
————————————————
最后我们放松一下眼睛
相关文章:

Python中使用C扩展详解
文章目录 1. Python/C API示例2. Cython示例3. ctypes关于C扩展的进一步讨论安全性和兼容性性能优化策略调试C扩展发布和分发C扩展 应用实例:加速矩阵乘法运算1. 准备C扩展代码2. 编译C扩展3. 在Python中使用C扩展 在Python中,使用C扩展是一种提高程序性…...

llama使用tutorial微调(windows版本)
Llama3-Tutorial/docs/assistant.md at main SmartFlowAI/Llama3-Tutorial GitHub 有一些命令需要修改 前期的安装还是要按照教程搞的 streamlit run ~/Llama3-Tutorial/tools/internstudio_web_demo.py \ ~/model/Meta-Llama-3-8B-Instruct 改为了 streamlit run .\Ll…...

MyBatis操作数据库(动态SQL)
1 动态SQL 动态SQL是MyBatis的特征之一,能够完成不同条件下不同的SQL拼接 1.1 <if>标签 在注册用户的时候,可能会有这样一个问题,由于注册分为两种字段:必填字段和非必填字段,如果在添加用户的时候有不确定的…...

python发票真伪查验开发文档、票据OCR、数电票查验
想象一下,只需一行行简洁的代码,复杂繁琐的发票审核工作瞬间变得井然有序。翔云发票查验开发文档详尽易懂,即便是Python新手也能迅速上手,搭建起自己的发票真伪查验系统。无论是纸质发票的扫描图像,还是电子发票的数据…...

Unity构建详解(12)——自动构建
【前言】 自动构建是指整个构建流程不需要人工操作,只需要输入启动构建指令即可获取构建结果。实现这样的自动构建需要满足以下条件: 支持命令行参数启动 我们不可能每次构建时都打开Unity去手动点击构建,必须支持通过命令行启动Unity自动执…...

中文编程降低了中文环境下编程入门的门槛
近年来,随着编程技术的普及和中文编程环境的日益成熟,越来越多的开发者开始使用中文进行编程。中文编程不仅提高了代码的可读性和理解性,而且在一定程度上降低了中文环境下编程的入门门槛。本文将详细探讨中文编程的优势,以及它如…...

通过内网穿透免费部署我们的springboot+vue项目 实现跟服务器一样的效果
前文讲到通过内网穿透能够实现远程访问个人电脑的静态资源。本文将讲解通过内网穿透实现远程访问本地的项目,实现跟部署到服务器一样的效果:前文链接:通过内网穿透实现远程访问个人电脑资源详细过程(免费)(…...

SMB攻击利用之-mimikatz上传/下载流量数据包逆向分析
SMB协议作为windows环境下最为常见的一种协议,在历史上出现过无数的通过SMB协议进行网络攻击利用的案例,包括针对SMB协议本身以及通过SMB协议实施网络攻击。 本文将介绍一种通过SMB协议的常见利用方式,即向远程主机传输mimikatz,作为我的专栏《SMB攻击流量数据包分析》中的…...

Mysql常见数据类型探索
Mysql常见数据类型探索 数值类型 MySQL 支持所有标准 SQL 数值数据类型。 这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC),以及近似数值数据类型(FLOAT、REAL 和 DOUBLE PRECISION)。 关键字INT是INTEGER的同义词,关键字DEC是…...

2024 年第四届长三角高校数学建模竞赛赛题B题超详细解题思路+问题一二代码分享
2024年第四届长三角数学建模竞赛B题详细解题思路 赛道B:人工智能范式的物理化学家 长三角分享资料(问题一代码论文思路)链接(18点更新): 链接:https://pan.baidu.com/s/1lteKvIWNZ4v-Gd7oOcg…...

干货速学!1+X电子商务数据分析:电子商务数据分析的流程
电商数据采集API接口 生活中的数据分析 日常工作和生活中处处都有数据分析的存在,比如消费者在购买不同商品前,经常会对儿“性价比”进行简单分析,价格表现为固定的货币数字。性能则具体体现在商品质量、客户收务等客观因素和客户对该商品的需…...

618好物推荐大赏:2024年必囤好物一网打尽,购物攻略助你抢购无忧!
在618购物狂欢节来临之际,我为大家精心挑选了一系列好物,它们不仅品质卓越,更能在日常生活中为我们带来无限便利与乐趣。这里的每一款产品都经过我严格筛选,只为给你最优质的购物体验。让我们一起在这个618,发现生活中…...

【MySQL】基础操作(DDL,DML,DCL,DQL)
安装教程自行搜索,网上有很多 用户名设置为 root密码设置为 123456可以不这样设置,但要记好用户名密码,相关的代码也要自行更改 打开命令提示符程序(winR打开输入cmd回车) 输入:mysql -uroot -p 回车输入密码即可进入命令行环境…...
工厂自动化升级改造(3)-Modbus与MQTT的转换
什么是MQTT,Modbus,见下面文章 工厂自动化升级改造参考(01)--设备通信协议详解及选型-CSDN博客文章浏览阅读608次,点赞9次,收藏6次。>>特点:基于标准的以太网技术,使用TCP/IP协议栈,支持高速数据传输和局域网内的设备通信。>>>特点:跨平台的通信协议,…...

InnoDB 事务处理机制
文章目录 前言1. 事务处理挑战1.1 事务机制处理的问题1.2 并发事务带来的问题 2. InnodDB 和 ACID 模型2.1 Innodb Buffer Pool2.2 Redo log2.3 Undo log2.4 应用案例 3. 隔离级别和锁机制3.1 事务隔离级别3.1.1 READ UNCOMMITTED3.1.2 READ COMMITTED3.1.3 REPEATABLE READ3.1…...

Thymeleaf
替代jsp 功能:服务器渲染(就是将服务器的数据展示在网页上) 1、MVC概念 model 模型 javaBean(User/Book/Order...) View视图 html 服务器的动态数据 Controller控制器 Servlet MVC是在表述层开发运用的一种设计理念。主张把封装数据…...

网络学习(一)|深入了解API网关:定义、功能和关键术语
文章目录 定义主要功能关键术语 定义 API 网关(API Gateway)是一个核心的服务架构组件,用于管理、路由和保护对后端服务的访问。它充当了系统内外的接口,负责接收来自客户端的请求,并将其路由到相应的后端服务&#x…...

基于yolov8+flask搭建一个web版本的网页模型预测系统
测试环境: anaconda3python3.8 torch1.9.0cu111 ultralytics8.2.2 首先我们将训练好的权重放在weights目录下面 并将名字改成yolov8n.pt,如果不想改可以在代码app.py都把路径改过来即可。然后我们打开 python app.py之后看到 我们点击选择文件支持图…...

【北京迅为】《iTOP-3588从零搭建ubuntu环境手册》-第8章 安装编译所需要的依赖包
RK3588是一款低功耗、高性能的处理器,适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用,RK3588支持8K视频编解码,内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…...

牛客热题:合并二叉树
牛客热题:二叉树与双向链表> 📟作者主页:慢热的陕西人 🌴专栏链接:力扣刷题日记 📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言 文章目录 牛客热题…...

conda 常用20个命令
conda常用20个命令 这些命令涵盖了Conda环境管理和包管理的常用功能,可帮助你有效地管理Python环境和软件包。 创建环境: conda create --name myenv这个命令用于创建一个名为myenv的新环境。你可以在--name后面指定环境的名称,并在其后加上…...

Git泄露(续)
接上一篇补充 git config --global user.name " " git config --global user.email 邮箱地址 配置用户名和邮箱 git commit 使其处于交互区,没有使用 -m,默认用vim 来编辑和提交信息 输入要提交的内容,然后按ESC建回到命令…...

clickhouse卸载与安装
ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS),来自于俄罗斯本土搜索引擎企业Yandex公司。它是为处理大规模数据集而设计的,并提供高性能和低延迟的查询支持。 注意:此教程的运…...

npm install [Error]
npm install 依赖的时候报错 依赖版本问题的冲突,忽视即可 使用 npm install --legacy-peer-deps...

Redisson分布式锁全解析:从基础到红锁,锁定高并发解决方案
1. 介绍Redisson和分布式锁的概念 1.1 Redisson简介 Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid, IMDG)。它不仅提供了对分布式和可伸缩数据结构的支持,还提供了多种分布式服务,包括但不限于分布式锁、集合、映射、计…...

RocketMQ-Dashboard 控制台使用详解
1 安装部署 具体部署启动请参考:RocketMQ从安装、压测到运维一站式文档_rocketmq benchmark压测-CSDN博客 RocketMq的dashboard,有运维页面,驾驶舱,集群页面,主题页面,消费者页面,生产者页面&…...

JSP+SQL学生成绩管理系统
Java版本:1.8 数据库:MySQL 框架:Spring Spring MVC MyBatis 服务器:Tomcat 前端解析框架:Thymeleaf 开发工具:Idea 2017 版本管理工具:Maven 版本控制工具:GitHub 经过对系统的需…...

5G工业路由器实现驾考科目三实时监控与远程控制
5G驾考路由器的应用主要体现在智能驾考系统中,其优势包括提高考试安全性、效率和规范性,同时杜绝违规行贿作弊的行为。 在驾考系统中,5G工业路由器是数据传输的桥梁设备。车载设备如摄像头、定位系统、硬盘录像机、传感器等,通过串…...

基于微信小程序+JAVA Springboot 实现的【智慧乡村旅游服务平台】app+后台管理系统 (内附设计LW + PPT+ 源码+ 演示视频 下载)
项目名称 项目名称: 基于微信小程序的智慧乡村旅游服务平台的设计与实现 项目技术栈 该项目采用了以下核心技术栈: 后端框架/库: Java SSM框架数据库: MySQL前端技术: 微信开发者工具、uni-app其他技术:…...

图片中的表格转成word用什么工具好?
2024年5月16日,周四上午 我推荐用免费的腾讯OCR表格识别v3体验网站 用手机文档模式拍下并转成黑白后,成功识别的概率还是非常大的 OCR Demo (tencent.com)https://ocrdemo.cloud.tencent.com/识别成功后,复制识别结果并粘贴到word文档里面就…...