我一直在尝试通过使用 prange 并行调用代码段内的函数来优化代码段。这要求 prange 块内的所有函数都使用 nogil 运行,因此我正在调整它们以不使用 gil。然而,当尝试调整其中一个函数时,我遇到了有关 Python 局部变量/临时变量的问题。功能如下:
cdef float output(Branch self):
cdef float output = 0.0
cdef Dendrite dendrite # This line is considered a python Local
cdef Branch branch # This line is considered a python Local
cdef int index = 0
while index < self.length:
if self.isDendrite:
dendrite = self.inputs[index]
output += dendrite.output()
else:
branch = self.inputs[index]
output += branch.output()
index += 1
return self.activation.eval(output) * self.weight
尝试将函数转换为运行 nogil 时,cython 返回以下错误消息:
Function declared nogil has Python locals or temporaries
指向函数头。
对于上下文,这些是 Branch 和 Dendrite 类拥有的字段(Node 是 Dendrite 引用的另一个 cdef 类):
cdef class Branch():
cdef:
np.ndarray inputs # holds either Dendrite or Branch objects (but never both)
float weight
floatFunc activation
bint isDendrite # used to determine if Dendrites or Branches are held
int length
cdef class Dendrite():
cdef:
float charge
Node owner # the class below
float weight
np.ndarray links # holds objects that rely on Node and Dendrite
floatFunc activation # C-optimized class
int length
cdef class Node:
cdef:
float charge
float SOMInhibition
np.ndarray senders # holds objects that rely on Node and Dendrite
int numSenders
np.ndarray position # holds ints
NodeType type # this is just an enum
np.ndarray dendrites # this holds Dendrite objects
int numDendrites
np.ndarray inputDendrites # holds Dendrite objects
int numInputDendrites
np.ndarray inputBranches # holds Branch objects
int numInputBranches
int ID
floatFunc activation # C-optimized class
我的猜测是,这与类将 numpy 数组作为字段这一事实有关,但 numpy 与 cython 兼容,并且不应该创建 python 对象(如果我理解正确的话)。
如果有人有任何建议如何使这些行不被算作 python 对象,我将不胜感激。谢谢!
Numpy 具有 Python 和 C API,您甚至可以这样做:
import numpy as np
cimport numpy as cnp
无论如何,一般来说,类和函数调用的开销非常小(我知道 Cython 将它们标记为深黄色,意味着昂贵,但通常它们会被调用几次来处理数百万个项目,至少如果您正确设计了系统的话)。
尝试在 Python 中定义类和不常见的函数,并将内存视图传递给 Cython 来完成大部分计算。这样你就可以释放 GIL,因为内存视图不是 Python 对象,你不必担心将所有内容转换为 C++(如果这是你的目标,为什么不先用 C++ 编写,然后编写一个 Cython 包装器来使用它)图书馆?)。