【问题标题】:Cython overhead on extension types in memoryview内存视图中扩展类型的 Cython 开销
【发布时间】:2016-01-04 11:53:34
【问题描述】:

我正在编译一个 Cython 模块,并使用 cython -a 命令检查了这段代码。

cdef INT_t print_info(Charge[:] electrons):
    cdef INT_t i, index
    for i in range(electrons.shape[0]):
        index = electrons[i].particleindex
    return index

原来是这样的

 + index = electrons[i].particleindex
    __pyx_t_4 = __pyx_v_i;
    __pyx_t_3 = (PyObject *) *((struct __pyx_obj_14particle_class_Charge * *) ( /* dim=0 */ (__pyx_v_electrons.data + __pyx_t_4 * __pyx_v_electrons.strides[0]) ));
    __Pyx_INCREF((PyObject*)__pyx_t_3);
    __pyx_t_5 = ((struct __pyx_obj_14particle_class_Charge *)__pyx_t_3)->particleindex;
    __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0;
    __pyx_v_index = __pyx_t_5;

Charge 是一个 cdef 扩展类型,我在这里尝试使用 memoryview 缓冲区Charge[:]。在这种情况下,Cython 似乎调用了一些 Python API,特别是已生成 __Pyx_INCREF((PyObject*)__Pyx_DECREF(((PyObject *)

我想知道是什么原因造成的,它会导致很多减速吗?这是我在论坛的第一篇文章,非常感谢任何cmets或建议!

PS:Charge对象定义为

charge.pyx

cdef class Charge:
    def __cinit__(Charge self):
        self.particleindex = 0     
        self.charge = 0
        self.mass = 0
        self.energy = 0
        self.on_electrode = False 

charge.pxd

cdef class Charge:
    cdef INT_t particleindex
    cdef FLOAT_t charge
    cdef FLOAT_t mass
    cdef FLOAT_t energy
    cdef bint on_electrode 

【问题讨论】:

  • INCREF,DECREF - 增加/减少参考(计数)。这是跟踪对 Python 对象的引用(用于垃圾收集)的一部分。 _pyx_t_3 是类Charge 的新(临时)对象,由索引创建。
  • 我建议显示定义Charge的代码。
  • 感谢您对我的主题的回复和编辑。定义有什么问题吗?
  • 因此,通过索引electrons[i],您正在创建对Charge 对象的临时引用。这就是INCREF 的注释。一旦partaicleindex 被“存储”在pyx_t_5 中,它就会将_pyx_t_3 扔掉,并减少引用计数。 INCREF/DEC 只是普通的 Python 簿记。
  • 感谢您的解释。这个过程对代码的速度有任何惩罚吗?如果是这样,有没有办法克服它?

标签: cython


【解决方案1】:

Cython 可能会更喜欢 Pythonic 代码。重写你的函数:

cdef INT_t print_info(Charge[:] electrons):
    cdef INT_t i, index
    for electron in electrons:
        index = electron.particleindex
    return index

然后再试一次。

【讨论】:

  • 感谢您的回复。我试过了,但它不起作用。这条线变得更加“黄色”。另外我认为它与 memoryview 缓冲区有关。当我只使用扩展类型作为参数时,比如 some_function(Charge electron),Cython 不会生成 API 层。
【解决方案2】:

不是内存视图,而是扩展类型。 Cython 扩展类型使用与 Python 对象相同的引用计数语义来处理。

可以使用<void*><PyObject*>(您可以从cpython.refcimport)获取并使用指向它们的指针,这些指针不会改变重新计数,但是指针显然没有任何方法或属性。在您尝试转换回扩展类型类型的那一刻,INCREF/DECREF 代码会重新出现。不过,这些说明非常快。

邮件列表上有一些关于扩展类型的非引用引用(即,可以访问对象数据)如何成为未来的新功能的讨论,但似乎对添加一个功能的热情不大,实际上,可能会导致大量“访问冲突”类型的可怕错误代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 2018-11-14
    • 2016-07-15
    • 1970-01-01
    • 2017-11-14
    相关资源
    最近更新 更多