加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

Python / Cython:存储在numpy数组中的类的开销

发布时间:2020-12-20 11:36:05 所属栏目:Python 来源:网络整理
导读:这种慢速代码可以通过改变结构来改进,但有时难以解决.我认为,原因来自存储在数组中的类.我听说内存视图用于链接 python和c数组,但我还是很新的(只有一些python知识). 有没有办法有效地做到以下几点? 一个示例类: cdef class ClassWithAdditionFunction: cd
这种慢速代码可以通过改变结构来改进,但有时难以解决.我认为,原因来自存储在数组中的类.我听说内存视图用于链接 python和c数组,但我还是很新的(只有一些python知识).

有没有办法有效地做到以下几点?

一个示例类:

cdef class ClassWithAdditionFunction:
    cdef double value

    def __init__(self,double value):
        self.value = value

    cpdef add_one(self):
        self.value += 1

功能缓慢:

cdef unsigned long int i,ii
cdef unsigned long int loops = pow(10,8)
cdef double value

addition_classes = np.array([None] * 10)

for i in range(len(addition_classes)):
    addition_classes[i] = ClassWithAdditionFunction(value=0)

for i in range(loops/10):
    for ii in range(10):
        addition_classes[ii].add_one()

非常感谢您的任何建议!

解决方法

你可以做一些小事情应该有所帮助.真正想要加速的代码行是addition_classes [ii] .add_one().如果你使用cython -a看看幕后真正发生了什么,你会看到你正在调用Pyx_GetItemInt,然后调用PyObject_GetAttr,然后调用PyObject_Call.您希望构造代码以避免这3个调用.

要避免GetItem调用,您需要使用numpy的缓冲区接口或内存视图.这告诉cython数组的结构,并允许它更有效地从数组中提取项目.在下面的示例中,我使用了内存视图.如果你做类似的事情,请确保该数组实际上是一个充满ClassWithAdditionFunction实例的数组,否则你可能会遇到段错误.

为了避免GetAttr调用,声明一个ClassWithAdditionFunction类型的变量并对该变量进行方法调用,这样cython就知道该变量具有该方法的编译版本,可用于更快的调用.

最后你已经用cpdef方法定义了add_one,但我建议你也添加一个返回类型.通常我们可以放空,但因为这是一个cpdef函数而不是cdef函数,你可以使用int代替.

如果把所有这些放在一起它应该看起来像:

import numpy as np
cimport cython

cdef class ClassWithAdditionFunction:
    cdef double value

    def __init__(self,double value):
        self.value = value

    cpdef int add_one(self):
        self.value += 1
        return 0

@cython.boundscheck(False)
@cython.wraparound(False)
def main():

    cdef:
        unsigned long int i,ii,loops = 10 ** 6
        ClassWithAdditionFunction addInstance
        double value,y

    addition_classes = np.array([None] * 10)
    cdef ClassWithAdditionFunction[:] arrayview = addition_classes

    for i in range(len(addition_classes)):
        addition_classes[i] = ClassWithAdditionFunction(value=0)

    for i in range(loops/10):
        for ii in range(10):
            addInstance = arrayview[ii]
            addInstance.add_one()

    return None

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读