0Pricing
Python Academy · 课时

为何使用 C 扩展?使用场景与权衡

了解何时以及为何使用原生 C 代码扩展 Python。

为何使用 C 扩展?使用场景与权衡 是 CoddyKit 上的免费 Python Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Python Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Python Academy 课程共包含 4 节课。

什么是 C 扩展

C 扩展是 Python 可以导入的编译型共享库(Linux/macOS 上为 .so,Windows 上为 .pyd)。它公开了用 C 实现的函数和类型。

# After building the extension:
import myext
result = myext.fast_sum([1, 2, 3, 4, 5])
print(result)   # 15 (computed in C)

何时使用 C 扩展

在以下情况下使用 C 扩展:处理受 CPU 限制的数值循环、封装现有的 C 库、绕过 GIL 以支持多线程工作负载,或实现极高的内存效率。

# Good candidates for C extensions:
# - NumPy array operations
# - Image processing pixel loops
# - Cryptographic primitives
# - Wrapping libpng, libssl, sqlite3

C 扩展的替代方案

在编写 C 之前,可以尝试 Cython(带注解的 Python → C)、Numba(即时编译),或 cffi/ctypes(用于调用现有的 C 库)。完整的 C 扩展功能最强大,但也是最复杂的选项。

# Cython example — almost Python syntax:
# def fast_sum(int[:] arr) -> int:
#     cdef int total = 0
#     for x in arr:
#         total += x
#     return total

GIL 注意事项

全局解释器锁(GIL)一次只允许一个线程执行 Python 字节码。C 扩展可以在执行纯 C 工作期间释放 GIL,从而实现真正的多线程并行。

# In a C extension:
# Py_BEGIN_ALLOW_THREADS
#     result = heavy_cpu_work(data);
# Py_END_ALLOW_THREADS
#
# Other Python threads run while this C code executes

权衡

C 扩展速度更快,但编写、调试和维护起来更困难。它们需要 C 知识、构建基础设施,以及特定于平台的测试。

# Trade-offs:
# + Fastest possible execution
# + Direct access to C libraries
# + Can release GIL
# - Complex build setup (setup.py / CMake)
# - Platform-specific compilation
# - Memory management is manual
# - Harder to debug

Python/C API 概览

Python/C API 提供用于创建 Python 对象、操作引用计数、解析参数、引发异常以及从 C 调用 Python 的宏和函数。

// C API basics:
// PyObject*  — pointer to any Python object
// Py_INCREF  — increment reference count
// Py_DECREF  — decrement reference count
// PyArg_ParseTuple — parse Python args from C
// PyErr_SetString  — raise a Python exception from C

setup.py 构建

请使用包含 Extension 对象的 setup.py 来编译和安装 C 扩展。

# setup.py
from setuptools import setup, Extension

setup(
    name="myext",
    ext_modules=[
        Extension("myext", sources=["myext.c"])
    ]
)

# Build:
# python setup.py build_ext --inplace

实际应用示例

Python 生态系统高度依赖 C 扩展:NumPy、图像处理库,以及标准库模块 json、hashlib 和 zlib 都使用了 C 扩展。

# NumPy is a C extension:
import numpy as np
a = np.arange(1_000_000)
result = a.sum()   # executed in C, 100x faster than pure Python
print(result)

Cython:更简单的路径

Cython 会将带注解的 Python 代码编译为 C 扩展。在编写原始 C 代码之前,请先从 Cython 开始——它要简单得多,而且通常可以达到原有速度的 90%。

# fib.pyx (Cython)
cpdef long fib(int n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

# Compile:
# cythonize -i fib.pyx
# import fib; fib.fib(40)

调试 C 扩展

请使用 GNU 调试器或 LLVM 调试器来调试 C 扩展崩溃。请在 CFLAGS 中启用 -g,并在不进行优化的情况下编译,以获得可读的堆栈跟踪。

# Compile with debug symbols:
# CFLAGS="-g -O0" python setup.py build_ext --inplace

# Debug:
# gdb python
# (gdb) run script.py
# (gdb) backtrace

# Valgrind for memory leaks:
# valgrind --tool=memcheck python script.py

测试 C 扩展

请通过 Python 接口使用 Python 测试框架来测试 C 扩展,无需专门的 C 测试框架。

# test_myext.py
import pytest
import myext

def test_fast_sum():
    assert myext.fast_sum([1, 2, 3]) == 6

def test_empty():
    assert myext.fast_sum([]) == 0

def test_type_error():
    with pytest.raises(TypeError):
        myext.fast_sum("not a list")

快速检查

与使用纯 Python 相比,编写 C 扩展的主要原因是什么?

总结

C 扩展是加速 Python 的最快方式:它们执行本机 C 代码,并且可以释放 GIL。调用现有 C 库时请使用 ctypes/cffi;带注解的 Python 到 C 编译请使用 Cython;只有在需要最大控制力时才编写原始 C 扩展。请始终通过 Python 接口进行测试。

常见问题解答

「为何使用 C 扩展?使用场景与权衡」课时是免费的吗?

是的 — 「为何使用 C 扩展?使用场景与权衡」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Python Academy 课程的其余内容,请升级到 CoddyKit PRO。 Python Academy 课程共包含 4 节课。

「为何使用 C 扩展?使用场景与权衡」这节课中我会学到什么?

了解何时以及为何使用原生 C 代码扩展 Python。 你通过在浏览器中直接运行的动手代码来练习 Python Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Python Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Python Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「为何使用 C 扩展?使用场景与权衡」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Python Academy 课中编写并运行代码吗?

能。每节 Python Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 为何使用 C 扩展?使用场景与权衡
  2. ctypes:从 Python 调用 C 库
  3. cffi:C 外部函数接口
  4. 编写 Python C 扩展模块
← 返回 Python Academy