问题
Introduction
scipy.integrate.odeint requires as its first argument, a function that computes the derivatives of the variables we want to integrate over (which I'll refer to as d_func
, for "derivative function" from now on).
d_func
has to be written by the user, in Python code. A great way to get a boost of performance using Numba is to @jit
the d_func
(because d_func
is called many times during integration).
I have questions about how to write performant code when d_func
is complicated enough that it needs a Python class object behind it.
Code setup
Here is a "cartoon" of my code:
- there is a module called
DynamicBox.py
- inside this module is a Python class,
DynamicBox
DynamicBox
has a bunch of attributes- some of these attributes are "phase variables" -- that is, they are the quantities I am interested in integrating
- some of these attributes are "parameters" -- that is, I use them to calculate the derivatives of the phase variables
I will have a bunch of functions that will take DynamixBox
phase variable or parameter attributes, in order to calculate relevant terms in the derivatives. That is:
- I will have a
d_func
d_func
itself will call lots of little helper functions to calculate relevant terms in the derivative, usingDynamixBox
attributes
Design choices
I have to make a choice, with the following options:
- either I can make
d_func
and all its helper functions methods ofDynamicBox
; - or I can make only
d_func
a method ofDynamicBox
, and all of its helper functions are in the same module asDynamicBox
, but not methods ofDynamicBox
; - or only the helper functions are methods of
DynamicBox
, butd_func
is just in the same module (DynamicBox.py
), and not a method ofDynamicBox
; - or neither the helper functions, nor d_func, are methods of DynamicBox.
Question
I do not know enough about Python to figure out which choice is best. The following questions I think would need answering.
Is it expensive to make instance attribute calls to get attributes or is it expensive only if you are in a function that is not a method of the class?
What if Numba is in play? For instance, will Numba like it better if I am
@jit
-ting normal functions instead of class methods?
回答1:
I can comment on the Numba portion of this question.
As other users have mentioned, attribute access in Numba leads to some overhead. For example, you might be tempted to write code like this:
class Foo(object):
def __init__(self, x):
self.x = x
@numba.jit
def dosomething(self, y):
for i in range(len(self.x)):
self.x[i] += y[i]
This will be slow, because Numba has to call into the Python layer for attribute access each time it encounters self.x
.
A better way to do the same thing would be this:
class Foo(object):
def __init__(self, x):
self.x = x
def dosomething(self, y):
_dosomething(self.x, y)
@numba.jit(nopython=True)
def _dosomething(x, y):
for i in range(len(x)):
x[i] += y[i]
Here there is no attribute access within the loop, and additionally we're able to add the nopython=True
argument, which will cause Numba to raise an error if the function has to fall back on any (slow) Python code. This nopython
argument is a great way to make sure that your Numba functions are as efficient as possible.
来源:https://stackoverflow.com/questions/30016845/design-heuristics-for-writing-python-classes-that-interact-with-scipy-integrate