PythonC扩展-维护状态
我需要用C编写一个Python扩展,我将使用它:PythonC扩展-维护状态,python,python-c-extension,Python,Python C Extension,我需要用C编写一个Python扩展,我将使用它: 对文件执行CPU密集型初始化 根据初始化的数据进行多个函数调用,以将结果返回给我;和 完成后释放内存 一种解决方案是在Python中实现一个“stateholder”类。当我在C中调用初始化时,它返回我将存储在Python状态对象中的初始化数据。然后每次我需要执行步骤(2),我都会将它传递给C函数。但是,由于Python端和C端之间发生了所有的数据穿梭/接口,因此这似乎非常低效 如果可能的话,我希望在C端使用状态对象来维护状态。Python端的初
我将如何在C端维护状态?首先,我将回答您实际提出的问题 在C中创建一个
struct状态
,就像不涉及Python一样
如果您不打算到处复制它们(只通过struct State*
传递它们),那么您只需执行(intptr\t)stateptr
即可获得Python的id。当然,您确实需要注意Python对象的生存期永远不会超过C对象的生存期,但这是可行的
如果出于某种原因确实需要复制/移动结构,或者需要更多帮助来管理状态(例如,将Python id视为弱引用),请为用例选择适当的集合(哈希表、树、数组等),然后将密钥作为id传递给Python
但是,我认为您可能优化了错误的部分。来回传递对象没什么,只是一个指针副本。重新计数可能是一个问题,但很少是这样,而且您从生命周期管理中获得的好处通常是值得的。可能影响性能的部分是您的C代码不断地将一组Python整数转换为Cint
s等。如果这是您的问题,只需创建一个带有C状态的C结构,并将其包装在一个Python对象中,该对象不会将任何内部内容暴露到Python中
最后,您真的需要任何优化吗?如果你在做CPU密集型的工作,我敢打赌,真正的工作完全掩盖了Python对象访问的成本,后者甚至不会出现在评测中。如果你还没有分析过,那绝对是你应该做的第一件事,因为这里的正确答案可能是“什么都不用做”
更进一步:如果你只是为了优化而用C写C代码,你确定你需要吗?在C语言中处理内存管理很烦人而且容易出错,在Python的C扩展模块中处理内存管理更是如此,当您还不知道它是如何工作的时候,第一次这样做几乎可以保证您会花费所有的时间来查找错误和泄漏,而不是编写实际的代码。因此,我将按顺序尝试以下操作,对每个操作进行分析,只有在列表速度太慢时才向下移动:
- 只需用Python编写算法,并使用现有的CPython解释器即可
- 确保你有一个最佳的算法
- 尝试PyPy而不是CPython
- 获取并尝试用尽可能少的更改编译Python代码
- 根据需要修改代码以利用Cython特性,如静态类型、直接调用C函数等
- 用C编写底层代码,用Cython或Python使用
编写中层代码(跟踪状态对象并向Python提供包装器的代码)李>ctypes
- 使用您喜欢的接口机制,用C编写整个低级和中级。这仍然可能不是原生的C API,除非您有很多经验并且正在做一些非常简单的事情
.pyx
示例,您会发现一些可以启发您解决方案的内容
我也同意其他人的观点:问问自己是否需要使用C语言,因为扩展类型会增加整个系统的复杂性。我认为你优化了错误的部分。来回传递对象没什么,它只是一个指针。它在之间来回转换,例如,
PyInteger
和int
反复转换,这会杀死你。因此,创建一个具有普通C状态(int
s等)的C结构,以及一个负责管理结构生命周期但不查看任何数据的Python包装器。要按照实际要求的方式执行操作,可以在C中创建哈希表、二叉树或结构数组,并传递哈希键、树键、,或者数组索引到Python以用作id…但更简单、更明显的是,如果您从不复制状态结构,只需将指针从struct state*
投射到intptr\t
并将其用作id。查看Cython。您可以用最少的麻烦创建与C代码对话的扩展类。@kwatford:一般来说,这是一个很好的提示,尽管我认为它不能直接回答OP的问题。另一方面,它可能间接地