Add documentation with tips for optimizing performance
This commit is contained in:
parent
be632e7a89
commit
70eef0ccf9
|
@ -59,6 +59,7 @@ User Guide
|
|||
contexts
|
||||
measurement
|
||||
defining
|
||||
performance
|
||||
|
||||
|
||||
More information
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
.. _performance:
|
||||
|
||||
|
||||
Optimizing Performance
|
||||
======================
|
||||
|
||||
Pint can impose a significant performance overhead on computationally-intensive problems. The following are some suggestions for getting the best performance.
|
||||
|
||||
.. note:: Examples below are based on the IPython shell (which provides the handy %timeit extension), so they will not work in a standard Python interpreter.
|
||||
|
||||
Use magnitudes when possible
|
||||
----------------------------
|
||||
|
||||
It's significantly faster to perform mathematical operations on magnitudes (even though your'e still using pint to retrieve them from a quantity object).
|
||||
|
||||
.. doctest::
|
||||
|
||||
In [1]: from pint import UnitRegistry
|
||||
|
||||
In [2]: ureg = UnitRegistry()
|
||||
|
||||
In [3]: q1 =ureg('1m')
|
||||
|
||||
In [5]: q2=ureg('2m')
|
||||
|
||||
In [6]: %timeit (q1-q2)
|
||||
100000 loops, best of 3: 7.9 µs per loop
|
||||
|
||||
In [7]: %timeit (q1.magnitude-q2.magnitude)
|
||||
1000000 loops, best of 3: 356 ns per loop
|
||||
|
||||
This is especially important when using pint Quantities in conjunction with an iterative solver, such as the `brentq method`_ from scipy:
|
||||
|
||||
.. doctest::
|
||||
|
||||
In [1]: from scipy.optimize import brentq
|
||||
|
||||
In [2]: def foobar_with_quantity(x):
|
||||
# find the value of x that equals q2
|
||||
|
||||
# assign x the same units as q2
|
||||
qx = ureg(str(x)+str(q2.units))
|
||||
|
||||
# compare the two quantities, then take their magnitude because
|
||||
# brentq requires a dimensionless return type
|
||||
return (qx - q2).magnitude
|
||||
|
||||
In [3]: def foobar_with_magnitude(x):
|
||||
# find the value of x that equals q2
|
||||
|
||||
# don't bother converting x to a quantity, just compare it with q2's magnitude
|
||||
return x - q2.magnitude
|
||||
|
||||
In [4]: %timeit brentq(foobar_with_quantity,0,q2.magnitude)
|
||||
1000 loops, best of 3: 310 µs per loop
|
||||
|
||||
In [5]: %timeit brentq(foobar_with_magnitude,0,q2.magnitude)
|
||||
1000000 loops, best of 3: 1.63 µs per loop
|
||||
|
||||
Bear in mind that altering computations like this **loses the benefits of automatic unit conversion**, so use with care.
|
||||
|
||||
A safer method: wrapping
|
||||
------------------------
|
||||
A better way to use magnitudes is to use pint's wraps decorator (See :ref:`wrapping`). By decorating a function with wraps, you pass only the magnitude fo an argument to the function body according to units you specify. As such this method is safer in that you are sure the magnitude is supplied in the correct units.
|
||||
|
||||
.. doctest::
|
||||
|
||||
In [1]: import pint
|
||||
|
||||
In [2]: ureg = pint.UnitRegistry()
|
||||
|
||||
In [3]: import numpy as np
|
||||
|
||||
In [4]: def f(x, y):
|
||||
return (x - y) / (x + y) * np.log(x/y)
|
||||
|
||||
In [5]: @ureg.wraps(None, ('meter', 'meter'))
|
||||
def g(x, y):
|
||||
return (x - y) / (x + y) * np.log(x/y)
|
||||
|
||||
In [6]: a = 1 * ureg.meter
|
||||
|
||||
In [7]: b = 1 * ureg.centimeter
|
||||
|
||||
In [8]: %timeit f(a, b)
|
||||
1000 loops, best of 3: 312 µs per loop
|
||||
|
||||
In [9]: %timeit g(a, b)
|
||||
10000 loops, best of 3: 65.4 µs per loop
|
||||
|
||||
.. _`brentq method`: http://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.brentq.html
|
Loading…
Reference in New Issue