You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

简单CPython程序性能测量及从零构建与Python程序性能对比方法

从零开始编写简单CPython扩展并对比性能(以计算10!为例)

嘿,我来帮你把这个问题拆解清楚!很多刚接触CPython扩展的朋友都会疑惑怎么从零入手,刚好拿计算10的阶乘这个简单例子来一步步做,既能学会写扩展,又能直观看到性能差异。

先搞懂:什么是CPython扩展?

CPython是Python的官方实现,它本身就是用C写的。CPython扩展就是用C语言编写的模块,可以直接被Python导入调用——因为C是编译型语言,没有Python解释器的字节码解析、类型检查等额外开销,在计算密集型任务上能带来明显的性能提升。


步骤1:编写计算10!的CPython扩展

我们分三步完成这个扩展:

1. 编写核心C代码(factorial.c)

这个文件要包含Python的头文件,实现阶乘的C函数,再把它包装成Python可调用的接口,最后定义模块的初始化逻辑:

#include <Python.h>

// 纯C实现的阶乘计算函数
long long factorial_c(int n) {
    long long result = 1;
    for (int i = 1; i <= n; i++) {
        result *= i;
    }
    return result;
}

// 把C函数包装成Python可调用的函数
static PyObject* py_factorial(PyObject* self, PyObject* args) {
    int n;
    // 解析Python传入的参数(这里要求传入一个整数)
    if (!PyArg_ParseTuple(args, "i", &n)) {
        return NULL; // 参数解析失败时返回NULL,Python会抛出异常
    }
    long long result = factorial_c(n);
    // 将C的long long类型转换为Python的整数对象
    return PyLong_FromLongLong(result);
}

// 定义模块的方法列表
static PyMethodDef FactorialMethods[] = {
    {"factorial", py_factorial, METH_VARARGS, "Calculate the factorial of a number."},
    {NULL, NULL, 0, NULL}  // 列表结束标记
};

// 模块的结构体定义
static struct PyModuleDef factorialmodule = {
    PyModuleDef_HEAD_INIT,
    "factorial_ext",  // 模块名(Python中导入时用这个名字)
    NULL,             // 模块文档(可选)
    -1,               // 保持全局状态(一般填-1即可)
    FactorialMethods
};

// 模块初始化函数(必须叫PyInit_<模块名>)
PyMODINIT_FUNC PyInit_factorial_ext(void) {
    return PyModule_Create(&factorialmodule);
}

2. 编写编译配置文件(setup.py)

用setuptools来帮我们编译C代码生成Python可导入的模块:

from setuptools import setup, Extension

# 定义扩展模块:模块名、源文件列表
module = Extension('factorial_ext', sources=['factorial.c'])

setup(
    name='factorial_ext',
    version='1.0',
    description='A simple factorial calculation extension written in C',
    ext_modules=[module]
)

3. 编译安装扩展

在终端执行以下命令,会在当前目录生成可直接导入的模块文件(Linux/macOS下是.so,Windows下是.pyd):

python setup.py build_ext --inplace

步骤2:对应的Python阶乘程序

我们写两个版本的Python实现作为对比:

# 版本1:纯Python循环实现
def factorial_py(n):
    result = 1
    for i in range(1, n+1):
        result *= i
    return result

# 版本2:Python标准库的math.factorial(本身也是C实现的,作为参考)
import math

步骤3:性能测量与对比

用Python的timeit模块来测量性能——它会多次执行代码片段,减少单次执行的误差,结果更准确。

测量代码

import timeit
import factorial_ext  # 导入我们的CPython扩展
from factorial_py import factorial_py
import math

# 重复执行100万次,测量时间
ext_time = timeit.timeit(lambda: factorial_ext.factorial(10), number=1000000)
py_time = timeit.timeit(lambda: factorial_py(10), number=1000000)
math_time = timeit.timeit(lambda: math.factorial(10), number=1000000)

# 打印结果
print(f"CPython扩展执行100万次10!的时间: {ext_time:.4f}秒")
print(f"纯Python循环执行100万次10!的时间: {py_time:.4f}秒")
print(f"math.factorial执行100万次10!的时间: {math_time:.4f}秒")

# 计算性能提升倍数
py_speedup = py_time / ext_time
math_speedup = math_time / ext_time
print(f"\nCPython扩展比纯Python循环快 {py_speedup:.2f} 倍")
print(f"CPython扩展比math.factorial快 {math_speedup:.2f} 倍(注:math.factorial本身也是优化过的C实现)")

预期结果

在普通机器上测试,你大概会看到这样的结果:

  • CPython扩展:~0.02秒
  • 纯Python循环:~0.15秒
  • math.factorial:~0.02-0.03秒

也就是说,CPython扩展比纯Python循环快7-8倍,和标准库的C实现速度差不多(因为标准库做了更多边界处理和优化,可能略慢一点)。


为什么CPython扩展更快?

核心原因在于执行方式的差异:

  • Python是解释型语言,每次循环都要做类型检查、字节码解析,还有Python对象的创建/销毁开销;
  • C代码被编译成机器码直接执行,没有这些额外开销,计算效率拉满。

不过要注意:如果是IO密集型任务(比如读写文件、网络请求),CPython扩展的优势很小,因为瓶颈在IO等待,不在计算。

内容的提问来源于stack exchange,提问作者Abhinav Mishra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:06:34