I have been trying to optimize a code segment by making calls to functions inside it parallel using prange. This requires that all the functions inside the prange block run with nogil, so I am in the process of adapting them to not use the GIL. However, when trying to adapt one of the functions I'm running into a problem regarding Python Locals/Temporaries. The function is below:
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
When trying to convert the function to run nogil, the following error message is returned by Cython:
Function declared nogil has Python locals or temporaries
pointing to the function header.
For context, these are the fields that the Branch and Dendrite classes own (Node is another cdef class that is referenced by Dendrite):
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
My guess is that this has something to do with the fact that the classes have NumPy arrays as fields, but NumPy is compatible with Cython and should not be making Python objects (if I understood correctly).
How can I make it so that those lines are not counted as Python objects?
It has been mentioned that untyped NumPy arrays do not provide much benefit in terms of performance. In the past I tried to type them during class declaration, but Cython threw a compile error when it saw the type identifiers in the class declaration. I do type the arrays in the initializer before assigning them to fields though, so does that still work, or is the typing during initialization not relevant?
self.inputsis annp.ndarraywhich contains objects and not typed objects. This can be the source of the error. Numpy object cannot contains custom native C types other than native primitive type (eg.np.int32,np.float64, etc.). The same thing applies with othernp.ndarray-typed attributes.np.ndarraywithout typing the element gives you very little advantage in Cython, and will require the GIL for most operations (except possibly accessing theshape)cdef classis a Python object so will need the GILcdef class(as you note) but you can use typed memoryviews which are their more modern replacement