Python中如何实现Python与C语言之间的相互调用

事情是这样的,首先我用 c 写了一个 python 模块,由于这个模块里涉及了大量与 python 环境无关的 io 和运算,于是我在进入模块的开始就释放了 GIL,结束前再获取 GIL,然后返回结果,模块现在自由地奔跑了起来。 模块跑到了一半,现在有一个功能用 C 来实现实在是太复杂了,我想用 python 来写这部分的代码,当然,我可以在这里获取 GIL,运行代码,再释放 GIL。但是原来的 python 环境本身任务就非常繁重,而我的模块中间想插入的 python 代码调用也非常频繁,因此在这里获取 GIL 似乎有点浪费性能,毕竟我插入的 python 代码与原来的环境其实没什么关系(我不需要原来 python 环境里的任何模块或者变量,也不需要创建什么让原来的环境访问)。因此我在思考能不能不获取原环境的 GIL,另外新起一个 python 环境来跑我插入的 python 代码,又或者是在没有 GIL 的情况下安全执行我的代码? 我目前做了一点尝试,但是结果基本就是 python 环境崩溃,不知道有没有人做过类似的工作可以提供一点经验?万分感谢


Python中如何实现Python与C语言之间的相互调用

9 回复

要不了解下 Cython


Python和C语言相互调用主要有三种主流方式:ctypes、C扩展和Cython。

1. ctypes(推荐用于调用现有C库) ctypes是Python标准库的一部分,可以直接加载动态链接库(.dll/.so)并调用其中的函数。

# example.c
#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

# 编译:gcc -shared -o libexample.so -fPIC example.c

# python调用
from ctypes import cdll, c_int

lib = cdll.LoadLibrary('./libexample.so')
lib.add.argtypes = [c_int, c_int]
lib.add.restype = c_int
result = lib.add(5, 3)
print(result)  # 输出8

2. Python C扩展(适合高性能模块开发) 通过Python C API编写扩展模块,性能最好但代码较复杂。

// examplemodule.c
#include <Python.h>

static PyObject* add(PyObject* self, PyObject* args) {
    int a, b;
    if (!PyArg_ParseTuple(args, "ii", &a, &b))
        return NULL;
    return PyLong_FromLong(a + b);
}

static PyMethodDef methods[] = {
    {"add", add, METH_VARARGS, "Add two integers"},
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef module = {
    PyModuleDef_HEAD_INIT,
    "example",
    NULL,
    -1,
    methods
};

PyMODINIT_FUNC PyInit_example(void) {
    return PyModule_Create(&module);
}

// setup.py
from distutils.core import setup, Extension
module = Extension('example', sources=['examplemodule.c'])
setup(name='example', ext_modules=[module])

// 安装:python setup.py build_ext --inplace

3. Cython(平衡开发效率与性能) Cython是Python的超集,可以编译成C扩展。

# example.pyx
def add(int a, int b):
    return a + b

# setup.py
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize("example.pyx"))

# 使用
import example
print(example.add(5, 3))

选择建议:

  • 快速调用现有C库 → ctypes
  • 开发高性能核心模块 → C扩展
  • 平衡开发效率和性能 → Cython

根据你的具体场景选合适方案就行。

考虑下 boost 库?

感谢回复,据我了解,cython 是把 python 代码编译一下加速执行,但是本质上还是需要 python 解释器来执行的,这种情况下不还是需要 GIL 锁吗?

感谢回复,之前没有接触过 boost 库,刚才简单了解了一下,库调 python 的时候似乎仍然面对 GIL 的问题?

起另一个进程创建 GIL,应该没啥问题吧?

我一般是获取原来的 GIL。创建一个新的 GIL 的话,理论上来说,一个进程跑一个 GIL,应该是不会有问题吧?

Cython 里面可以写纯 C 代码, 释放 GIL 有直接语法支持:nogil, 当然 nogil 块里面不能有任何 Python 对象.

看你这难解难分的设计方法, Python/Cython/C 混编可能是最好的办法了. 个人经验来讲, 无论是 Python 调用 C, 还是 C 调用 Python, Cython 搭桥都是最简单直观的, 可以避免直接处理 Python C API, 这些 Cython 都帮你自动翻译好了.

回到顶部