Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PythonC扩展-维护状态_Python_Python C Extension - Fatal编程技术网

PythonC扩展-维护状态

PythonC扩展-维护状态,python,python-c-extension,Python,Python C Extension,我需要用C编写一个Python扩展,我将使用它: 对文件执行CPU密集型初始化 根据初始化的数据进行多个函数调用,以将结果返回给我;和 完成后释放内存 一种解决方案是在Python中实现一个“stateholder”类。当我在C中调用初始化时,它返回我将存储在Python状态对象中的初始化数据。然后每次我需要执行步骤(2),我都会将它传递给C函数。但是,由于Python端和C端之间发生了所有的数据穿梭/接口,因此这似乎非常低效 如果可能的话,我希望在C端使用状态对象来维护状态。Python端的初

我需要用C编写一个Python扩展,我将使用它:

  • 对文件执行CPU密集型初始化
  • 根据初始化的数据进行多个函数调用,以将结果返回给我;和
  • 完成后释放内存
  • 一种解决方案是在Python中实现一个“stateholder”类。当我在C中调用初始化时,它返回我将存储在Python状态对象中的初始化数据。然后每次我需要执行步骤(2),我都会将它传递给C函数。但是,由于Python端和C端之间发生了所有的数据穿梭/接口,因此这似乎非常低效

    如果可能的话,我希望在C端使用状态对象来维护状态。Python端的初始化调用不会返回所有的初始化数据,而只返回一个ID,这样它就可以在后续调用中需要时引用C状态对象


    我将如何在C端维护状态?首先,我将回答您实际提出的问题

    在C中创建一个
    struct状态
    ,就像不涉及Python一样

    如果您不打算到处复制它们(只通过
    struct State*
    传递它们),那么您只需执行
    (intptr\t)stateptr
    即可获得Python的id。当然,您确实需要注意Python对象的生存期永远不会超过C对象的生存期,但这是可行的

    如果出于某种原因确实需要复制/移动结构,或者需要更多帮助来管理状态(例如,将Python id视为弱引用),请为用例选择适当的集合(哈希表、树、数组等),然后将密钥作为id传递给Python

    但是,我认为您可能优化了错误的部分。来回传递对象没什么,只是一个指针副本。重新计数可能是一个问题,但很少是这样,而且您从生命周期管理中获得的好处通常是值得的。可能影响性能的部分是您的C代码不断地将一组Python整数转换为C
    int
    s等。如果这是您的问题,只需创建一个带有C状态的C结构,并将其包装在一个Python对象中,该对象不会将任何内部内容暴露到Python中

    最后,您真的需要任何优化吗?如果你在做CPU密集型的工作,我敢打赌,真正的工作完全掩盖了Python对象访问的成本,后者甚至不会出现在评测中。如果你还没有分析过,那绝对是你应该做的第一件事,因为这里的正确答案可能是“什么都不用做”

    更进一步:如果你只是为了优化而用C写C代码,你确定你需要吗?在C语言中处理内存管理很烦人而且容易出错,在Python的C扩展模块中处理内存管理更是如此,当您还不知道它是如何工作的时候,第一次这样做几乎可以保证您会花费所有的时间来查找错误和泄漏,而不是编写实际的代码。因此,我将按顺序尝试以下操作,对每个操作进行分析,只有在列表速度太慢时才向下移动:

    • 只需用Python编写算法,并使用现有的CPython解释器即可
    • 确保你有一个最佳的算法
    • 尝试PyPy而不是CPython
    • 获取并尝试用尽可能少的更改编译Python代码
    • 根据需要修改代码以利用Cython特性,如静态类型、直接调用C函数等
    • 用C编写底层代码,用Cython或Python使用
      ctypes
      编写中层代码(跟踪状态对象并向Python提供包装器的代码)
    • 使用您喜欢的接口机制,用C编写整个低级和中级。这仍然可能不是原生的C API,除非您有很多经验并且正在做一些非常简单的事情
    查看python到C的简单桥接。那里的文档有很多例子——我链接到一个页面,该页面解释了如何构建某种状态对象,并解释了内存问题

    这是一个用cython/pyrex编写的(github)示例,一个相当奇特的I/O示例。根据我的经验,我们已经使用I/O例程将以压缩格式封送到磁盘的自定义对象进行了滚动,例如,在内存中,cython代码负责处理python可见的内容(例如自定义滚动)

    我最好的建议是,您可以搜索
    .pyx
    示例,您会发现一些可以启发您解决方案的内容


    我也同意其他人的观点:问问自己是否需要使用C语言,因为扩展类型会增加整个系统的复杂性。

    我认为你优化了错误的部分。来回传递对象没什么,它只是一个指针。它在之间来回转换,例如,
    PyInteger
    int
    反复转换,这会杀死你。因此,创建一个具有普通C状态(
    int
    s等)的C结构,以及一个负责管理结构生命周期但不查看任何数据的Python包装器。要按照实际要求的方式执行操作,可以在C中创建哈希表、二叉树或结构数组,并传递哈希键、树键、,或者数组索引到Python以用作id…但更简单、更明显的是,如果您从不复制状态结构,只需将指针从
    struct state*
    投射到
    intptr\t
    并将其用作id。查看Cython。您可以用最少的麻烦创建与C代码对话的扩展类。@kwatford:一般来说,这是一个很好的提示,尽管我认为它不能直接回答OP的问题。另一方面,它可能间接地