ctypes 与 C 扩展

Posted

技术标签:

【中文标题】ctypes 与 C 扩展【英文标题】:ctypes vs C extension 【发布时间】:2011-12-25 09:56:20 【问题描述】:

我有一些用 C 语言编写的用于游戏项目的函数。这些函数被调用很多次(大约每秒 2000-4000 次)。这些函数是用 C 语言编写的,以实现原始速度。

现在,我将这些函数包含到 Python 中的最简单方法是使用 ctypes。另一种方法是围绕这些函数编写 Python 的 C 扩展(这需要相当多的额外工作)。于是我就想,不包括DLL的初始加载,ctypes的开销有多大?


我使用的是 Python 2.7(标准 CPython 版本),我不想使用像 Cython 这样的外部库。

我知道之前有人问过这个问题,但我没有看到太多关于两个选项之间性能比较的信息。

【问题讨论】:

好吧,PyPy 的 JIT 可以为 ctypes 调用生成非常棒的代码,因为一两次发布。你可能想试一试。我不会将此作为答案发布,因为我手头没有确凿的数据,并且不清楚切换口译员是否适合您。 我希望开销是相似的。 @Delnan:这是一款我要发布的游戏——也将发布到 linux。我不能要求我的用户安装 PyPy。 来自python官方文档:“请注意,如果您的用例是调用C库函数或系统调用,您应该考虑使用ctypes模块而不是编写自定义C代码。ctypes不仅让您编写 Python 代码以与 C 代码交互,但它比编写和编译通常将您与 CPython 联系在一起的扩展模块在 Python 实现之间更具可移植性。 【参考方案1】:

我比较了 C 扩展与 ctypes 包装器的性能。在我的特定测试中,差异约为 250 倍。对 C 库进行了多次调用,因此 ctypes 包装器也在执行 Python 代码。 C 库的运行时间非常短,这使得 Python 代码的额外开销更加显着。所以这个比例对你来说可能会有所不同,但对我来说很重要。

【讨论】:

那么哪一个慢了 250 倍? @delnan:从他的回答中我可以看出 ctypes 包装器速度较慢。【参考方案2】:

直接 C 编码的接口有可能会快得多。瓶颈是从 Python 到 C 的接口,并且编组参数和结果可能涉及例如复制字符串或将 Python 列表转换为 C 数组/从 C 数组转换。如果您有一个循环进行数百次这样的调用,并且不必为每个调用单独编组一些数据,那么您所要做的就是在 C 中重新编码循环,您就可以大大减少瓶颈. ctypes 没有给你这个选项:你所能做的就是直接调用现有的函数。

当然,这完全取决于您调用的函数类型以及传递的数据类型。可能是您无法减少开销,在这种情况下,我仍然希望 ctypes 速度较慢,但​​可能不会显着。

最好的办法是将一些以每种方式编写的代码示例放在一起并对其进行基准测试。否则,对于一个明确的答案来说,变量太多了。

【讨论】:

我们所说的数据是位掩码(用于碰撞)。我已经准备好一个 C 实现,在 Python 代码中传递的唯一数据是布尔值、坐标和新的 Python 位掩码类(它只包含一个指向实际数据本身的指针,它存在于 C 代码中)。跨度> 对于位图,也许还可以探索 numpy.除了底层原生类型之外,内置的 Python 位图支持相当慢。

以上是关于ctypes 与 C 扩展的主要内容,如果未能解决你的问题,请参考以下文章

使用ctypes实现python类型和C语言类型之间的相互转化

通过 ctypes 使用扩展 dll 中的类需要帮助

ctypes给扩展模块中的函数传递数组和结构体

ctypes获取扩展模块中函数的返回值

使用 distutils 构建基于 ctypes 的 C 库

ctypes给扩展模块中的函数传递回调函数