Python C扩展实践&性能对比

Python、C、C扩展、Cython 差异对比,98%的人都不知道 我们以简单的斐波那契数列为例,来测试一下它们执行效率的差异。 上面便是 C 实现的一个斐波那契数列,可能有人好奇为什么我们使用浮点型,而不是整型呢?答案是 C 的整型是有范围的,所以我们使用 double,而且 Python 的 float 在底层对应的是 PyFloatObject、其内部也是通过 double 来存储的。C 扩展:然后是 C 扩展,注意:C 扩展不是我们的重点,写 C 扩展和写 Cython 本质是一样的,都是为 Python 编写扩展模块,... 阅读详情

C扩展实践

因为性能等一些原因,希望用C来扩展python。有多种方法,例如:

  • ctypes调用so
  • cython
  • python接口的C函数

这里阐述最后一种方式的实现。

  1. 首先需要 #include <Python.h>
  2. 需要实现下面三个函数:
static PyObject *funcName(PyObject *self, PyObject *args)
    /* 函数定义 */
static PyMethodDef methodsList[]
    /* 方法映射 */
PyMODINIT_FUNC initModule()
    /* Module初始化(python3 Module的定义和初始化略有不同,见下面示例代码) */

完整代码:

#include <Python.h>
#include <math.h>

#define PI acos(-1)

#if PY_MAJOR_VERSION >= 3
#define PY3K
#endif

void initcmath(void); /* Forward */

main(int argc, char **argv)
{
    /* Pass argv[0] to the Python interpreter */
    Py_SetProgramName(argv[0]);

    /* Initialize the Python interpreter.  Required. */
    Py_Initialize();

    /* Add a static module */
    initcmath();

    /* Define sys.argv.  It is up to the application if you
       want this; you can also leave it undefined (since the Python
       code is generally not a main program it has no business
       touching sys.argv...)

       If the third argument is true, sys.path is modified to include
       either the directory containing the script named by argv[0], or
       the current working directory.  This can be risky; if you run
       an application embedding Python in a directory controlled by
       someone else, attackers could put a Trojan-horse module in the
       directory (say, a file named os.py) that your application would
       then import and run.
    */
    PySys_SetArgvEx(argc, argv, 0);

    /* Do some application specific code */
    printf("Hello, brave new world\n\n");

    /* Execute some Python statements (in module __main__) */
    PyRun_SimpleString("import sys\n");
    PyRun_SimpleString("print sys.builtin_module_names\n");
    PyRun_SimpleString("print sys.modules.keys()\n");
    PyRun_SimpleString("print sys.executable\n");
    PyRun_SimpleString("print sys.argv\n");

    /* Note that you can call any public function of the Python
       interpreter here, e.g. call_object(). */

    /* Some more application specific code */
    printf("\nGoodbye, cruel world\n");

    /* Exit, cleaning up the interpreter */
    Py_Exit(0);
    /*NOTREACHED*/
}

int fastfactorial(int n){
 if(n<=1)
 return 1;
 else
 return n * fastfactorial(n-1);
}

double calculatearea(float r){
    double s;
    float r1, r2, r3, r4, r5;

    r1 = cosf(r);
    r2 = sinf(r);
    r3 = log10(r);
    r4 = PI;
    r5 = 666.666;
    r = (((r1 + r2) - r3) * r4)/r5;

    s = PI * pow(r, 2);
    return s;
}

static PyObject* factorial(PyObject* self, PyObject* args){
int n;
if (!PyArg_ParseTuple(args,"i",&n))
  return NULL;
int result = fastfactorial(n);
return Py_BuildValue("i",result);
}

static PyObject* do_calculation(PyObject* self, PyObject* args){
float n;
if (!PyArg_ParseTuple(args,"f",&n))
  return NULL;
double result = calculatearea(n);
return Py_BuildValue("d",result);
}

static PyMethodDef mainMethods[] = {
 {"factorial", factorial, METH_VARARGS, "Calculate the factorial of n"},
 {"do_calculation", do_calculation, METH_VARARGS, "Calculate the area of r"},
 {NULL, NULL, 0, NULL}
};

#ifdef PY3K
// module definition structure for python3
static PyModuleDef cmath = {
 PyModuleDef_HEAD_INIT,
 "cmath","Factorial Calculation",
 -1,
 mainMethods
};

PyMODINIT_FUNC PyInit_cmath(void){
 return PyModule_Create(&cmath);
}
#else
// module initializer for python2
PyMODINIT_FUNC initcmath(void) {
	// PyImport_AddModule("factorial");
    (void) Py_InitModule("cmath", mainMethods);
}
#endif

编译(使用distutils):

from distutils.core import setup, Extension

    factorial_module = Extension('cmath', sources=['cmath.c'])
    setup(name='MathExtension',
          version='1.0',
          description='This is a math package',
          ext_modules=[factorial_module]
          )

性能对比

使用上面完整代码中的calculatearea做运算性能对比,在python中做同样实现:

import cmath
import timeit
import math


def do_calculation(r):
    r1 = math.cos(r)
    r2 = math.sin(r)
    r3 = math.log10(r)
    r4 = math.pi
    r5 = 666.666
    r = (((r1 + r2) - r3) * r4)/r5
    return math.pi * r * r


if __name__ == '__main__':
    print do_calculation(555.555)
    print cmath.do_calculation(555.555)

    # print sys.modules['__main__']
    #
    radius = 666.666
    num = 10000000
    t = timeit.Timer("cmath.do_calculation(%f)" % (radius), "import cmath")
    print "C function", t.timeit(num), "sec"

    t2 = timeit.Timer("sys.modules['__main__'].do_calculation(%f)" % (radius))
    print "Python function", t2.timeit(num), "sec"

执行10000000次对比耗时:

OK,C实现的方案相同运算速度远快于python实现,目的达到。

应用-Python C扩展的隐藏性能开销 另一方面,Rust 具有内存安全、线程安全,并且是一种比 C/C++ 更高级的语言,同时具有相同的性能。因此,NumPy 数组内部存储数字不是作为 Python 列表的 Python 整数,而是作为 C 数组的 C 整数。事实证明,当我们将更多的工作移入像 Rust 的 Ranges 这样的高级构造时,我们最终得到了一个更聪明的解决方案。是用 C 编写的,实际的数学运算非常快,正如我们将在下面看到的。这相当不错,甚至比 NumPy 的实现更快,而且我们不需要创建整个数组的开销。 阅读详情

相关推荐

I2S时序及音频驱动

I2S、音频驱动

qq_41882586的博客 3946

PySys_SetArgv():no mem for sys.argv

在linux中编写C调用python程序时,进行python环境初始化,之后紧跟着使用PySys_SetArgv()函数,在编译时报错:no mem for sys.argv(PySys_SetArgv()函数用于设置python的sys.argv)查看编译过程信息有如图所示的warning,于是考虑是数据类型不对导致的错误,但是C主函数传进来的参数只能是char *argv[],所以在编写程序内部将char **转为wchar_t **

qq_43493425的博客 514

【AutoDL + Langchain-Chatchat】从零构建高效本地 RAG 知识库问答系统:实战保姆级教程(含避坑指南)

本文详细阐述如何在AutoDL云平台,如何利用Langchain-Chatchat构建高效的本地RAG知识库问答系统,并深入解析RAG架构。从环境搭建到实战部署,从问题排查到性能优化,提供一份全面实用的指南,助力开发者快速构建智能问答应用。

拾光夕拾的博客 1803

python 运行脚本附带参数_运行带有参数的python脚本

好像您正在使用Python.h中的python开发API寻找答案。这是您应该工作的一个例子:#My python script called mypy.pyimport sysif len(sys.argv) != 2:sys.exit("Not enough args")ca_one = str(sys.argv[1])ca_two = str(sys.argv[2])print "My com...

weixin_39938724的博客 616

用Docker-Compose三节点部署生产级Doris集群:从配置文件到故障转移

本文详细介绍了如何使用Docker-Compose部署一个生产级的三节点Apache Doris集群。内容涵盖从核心架构理解、配置文件编写到集群初始化验证的全过程,并重点讲解了如何实现高可用、数据持久化、健康检查以及故障转移等生产级运维关键点,为中小团队提供了一种在容器化便利性与系统稳定性间取得平衡的可靠部署方案。

kkk56的博客 856

CTFshow-pwn入门-前置基础pwn32-pwn34

CTFshow-pwn入门-前置基础pwn32-pwn34

你们de4月天的博客 1130

python最小解释器制作

平时经常用用到python脚本来实现一些小功能,可以通过pyinstaller之类的工具把py文件编译成exe程序,可是编译出来的程序动辄3mb以上,太大了很不爽。、、 我就想能不能把py编译成更小一点的exe。首先想到的是把py代码转换为c++代码,网上搜了很久也木有这样的工具。又一想,有没有python精简版之类的python库,又搜索很久没找到。 后来想到,自己编译python核心库,通...

haart的专栏 1891

RK3588部署Zipformer模型问题总结

本文分享了在RK3588嵌入式设备上部署小米Zipformer语音识别模型时遇到的问题及解决方法。主要遇到两个问题:1)在rknn_model_zoo例程编译时出现静态库版本不兼容,通过重新编译kaldi-native-fbank库并修改链接路径解决;2)sherpa-onnx编译时提示缺少portaudio库,通过修改编译脚本启用相关宏定义后成功编译。最终成功在RK3588上运行Zipformer模型,测试结果显示该模型具有较好的识别效果和实时性(RTF=0.22),验证了其在边缘设备上的适用性。

pkyang2004的博客 2144

c传字符串给python_如何将命令行参数作为字符串传递给从C执行的嵌入式Python脚本?...

我有一个C程序,它公开了一个Python接口来执行用户的嵌入式Python脚本.用户插入要运行的Python脚本的路径和命令行参数.然后脚本执行完毕boost::python::exec_file(filename, main_globals, main_globals)要将命令行参数传递给Python脚本,我们必须通过Python C-API函数设置它们PySys_SetArgv(int arg...

weixin_28814119的博客 360

基于STM32设计的智能水母投喂器(华为云IOT)_170

本项目利用STM32单片机控制各种传感器和水泵等设备,能够自动检测和调整水温和水质等参数,自动换水,自动供氧等等,充分满足了水母的养殖要求和需要。同时,根据水母喜欢的光环境,添加了RGB氛围灯,以及可以手动控制的喂食器等功能,提升了水母养殖的便利性和趣味性。

8805

uniapp - web-view嵌套H5网页白屏问题,<web-view>页面跳转出现白屏情况,强力解决uniapp嵌套webview页面时出现无法加载并白屏(无论本地还是线上H5网页链接都能解决)

uniapp微信小程序,uniapp APP端,uni-app web-view嵌套H5项目白屏问题分析及解决,uniapp嵌套webview页面时,出现白屏,uniapp <web-view>页面跳转出现白屏解决方法,uniapp <web-view>页面跳转出现白屏解决方法,解决uniapp的web-view打开网页在老手机上出现白屏的问题,uni-app web-view白屏处理,引入本地网页白屏,WebView 加载不出网页,一片空白webview白屏加载不出来,使用webview加载链接后白屏,u

🏆 前端领域优质创作者 1万+

C调用Python ‘sys‘ has no attribute ‘argv‘报错

1.问题描述 在通过C调用Python执行 plt.figure('Filter')

jianhui777的博客 1319

C#实现Socket通信同时监听多客户端(附完整源码)

C#实现Socket通信同时监听多客户端(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 427

python c 扩展 ctype 以及 效率对比

python开发效率高,第三方库资源丰富,而且可以用C/C++扩展。(基于python官方文档)   今天研究了用Ctype 来写python的扩展,用的是2.x版本的,刚开始还弄错了,看的是3.x版本的文档,浪费了不少时间。 首先将用C/C++ 编写python扩展吧; 我是在widows下,用的 vs2010 express,新建一个win32  DLL工程 然后在源码里面增加下面代

吐槽NLP & ML 4142

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Python中使用C扩展详解

Python中使用C扩展详解

qqrrjj2011的博客 2515

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

CPython 3.16 弃用生成器与协程创建类 C API:PyGen_New / PyCoro_New / PyAsyncGen_New 迁移指南

CPython 3.16 起,`PyGen_New`、`PyGen_NewWithQualName`、`PyCoro_New` 与 `PyAsyncGen_New` 四个面向"帧对象(frame)"创建生成器/协程/异步生成器对象的 C API 被正式标记为弃用(deprecated),并计划在 3.18 移除。本文基于 CPython 官方文档与源码,解析这四个函数的用途、弃用原因、底层实现、弃

gitblog_00166的博客 699

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

mypyc vs C扩展:终极Python性能优化指南与开发效率深度对比

在Python开发中,性能优化始终是开发者关注的核心议题。当项目需要突破Python解释器的性能瓶颈时,开发者通常面临两种选择:使用C扩展或采用mypyc编译器。本文将深入对比这两种方案的性能表现与开发效率,帮助你为项目选择最优的性能优化路径。 ## 🚀 性能表现:mypyc与C扩展的基准测试 mypyc作为mypy项目的官方编译器,通过将Python代码编译为C扩展来提升执行速度。根据[m

gitblog_00374的博客 1137

Python C 扩展开发:性能优化与应用

Python C 扩展是指用 C 或 C++ 编写的一组函数,这些函数能够被 Python 解释器调用。通过这种方式,我们可以直接利用 C/C++ 的高性能特性来加速 Python 程序中的特定部分。Python 官方提供了名为 "C API" 的接口,允许开发者轻松地创建这样的扩展模块。

2501_91139925的博客 1685

Python调用C/Rust扩展性能对比(真实压测数据曝光)

深入解析Python与Rust扩展模块的性能对比,揭示高频计算场景下性能优化核心方法。通过真实压测数据展示Rust在内存安全与执行效率上的显著优势,助你选择更优扩展方案。值得收藏

ProceSeed的博客 914

13. Python与C扩展

Python与C扩展的结合为性能关键型任务提供了强大支持,可根据项目需求选择。重点在于平衡开发效率与运行时性能,同时确保内存安全和跨平台兼容性。、C扩展模块、Cython或。

qq_17275369的博客 719

WebdriverIO DevTools Trace Mode 实战指南:无头化轨迹采集、保留策略与回放

Trace Mode 是 WebdriverIO DevTools 服务(`@wdio/devtools-service`)中的一套**无头化采集管线**:不开 DevTools UI 窗口,在会话结束时把一次运行的所有用户可见操作、网络请求、DOM 快照、截图与可访问性树写入一个**可移植的轨迹产物**,供离线回放、AI-Agent 对比以及 CI 产物归档使用。本文以 [Trace Mode

gitblog_01085的博客 297
上一篇: Android AsyncTask使用基础
ronniewy
博客等级 码龄15年 0粉丝 14原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值