Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Spoiler alert: You can make your Python faster

Spoiler alert: You can make your Python faster

Going through a couple of misconceptions on why python is slow and how to make it faster.

Given as a talk to Theoretical Systems Biology group at Imperial College.

Please see the accompanying demo: http://lukauskas.co.uk/article/2014/02/12/how-to-make-python-faster-without-trying-that-much/

Avatar for Saulius Lukauskas

Saulius Lukauskas

February 04, 2014
Tweet

More Decks by Saulius Lukauskas

Other Decks in Programming

Transcript

  1. Outline • Why is Python Slower than C • Implementations

    of Python • Idioms are important • Demo: minimal-effort-required optimisations of sample code
  2. Structs in python ? class Point(object): x, y = None,

    None def __init__(self, x, y): self.x, self.y = x, y
  3. Objects are slower in standard Python def sum_(points): sum_x, sum_y

    = 0, 0 for point in points: sum_x += point['x'] sum_y += point['y'] return sum_x, sum_y ! def sum_(points): sum_x, sum_y = 0, 0 for point in points: sum_x += point.x sum_y += point.y return sum_x, sum_y
  4. Objects are slower in standard Python def sum_(points): sum_x, sum_y

    = 0, 0 for point in points: sum_x += point['x'] sum_y += point['y'] return sum_x, sum_y ! def sum_(points): sum_x, sum_y = 0, 0 for point in points: sum_x += point.x sum_y += point.y return sum_x, sum_y 186 µs 201 µs
  5. Implementation is the key def sum_(points): sum_x, sum_y = 0,

    0 for point in points: sum_x += point.x sum_y += point.y return sum_x, sum_y In standard python, this is equivalent to dict(point)[‘x’] not a struct
  6. Standard Python implementation: CPython • Most commonly used implementation of

    Python • “C” stands for, well, C. • Can run native C code from python. • Designed to be reference rather than an optimised implementation
  7. Smart python interpreters: PyPy • http://pypy.org/ • Fast, compliant alternative

    implementation of the Python language (2.7.3 and 3.2.3). • Just-in-time (JIT) compilation • On (geometric) average of all benchmarks 6.2 times faster than CPython • Cannot run C code natively • Does not support numpy, yet
  8. Objects are slower in standard Python def sum_(points): sum_x, sum_y

    = 0, 0 for point in points: sum_x += point['x'] sum_y += point['y'] return sum_x, sum_y ! def sum_(points): sum_x, sum_y = 0, 0 for point in points: sum_x += point.x sum_y += point.y return sum_x, sum_y 186 µs 201 µs
  9. Under PyPy def sum_(points): sum_x, sum_y = 0, 0 for

    point in points: sum_x += point['x'] sum_y += point['y'] return sum_x, sum_y ! def sum_(points): sum_x, sum_y = 0, 0 for point in points: sum_x += point.x sum_y += point.y return sum_x, sum_y 186 µs 201 µs 21.6 µs 3.75 µs
  10. Idiom #1: Loops int ans[N]; for (int i=0; i <

    N; i++) { int datapoint = data[i]; ans[i] = do_something_with(datapoint); }
  11. Naive Pythonic implementation ans = [] for i in range(N):

    datapoint = data[i] ans.append(do_something_with(datapoint)) Takes 335 µs to run in my test
  12. Naive Pythonic implementation ans = [] for i in range(N):

    datapoint = data[i] ans.append(do_something_with(datapoint)) Allocates a list [0, 1, 2, … , N-1] to loop through
  13. Naive Pythonic implementation ans = [] for i in range(N):

    datapoint = data[i] ans.append(do_something_with(datapoint)) Allocates a list [0, 1, 2, … , N-1] to loop through just to access i-th data point
  14. Idiom for looping through lists ans = [] for datapoint

    in data: ans.append(do_something_with(datapoint)) Takes 290 µs to run in my test (13.4% faster)
  15. Idiom for applying function to lists map(do_something_with, data) Takes 189

    µs to run in my test (35% faster than previous)
  16. Light Reading: 10 Main Idioms of Python • Safe Hammad

    has recently compiled a list of ten main python idioms. • It is a very short read of best practices. • Have a look: • http://safehammad.com/downloads/python- idioms-2014-01-16.pdf
  17. Another JIT implementation: Numba • http://numba.pydata.org/ • Unlike PyPy, it

    is not a separate implementation of python • Supports numpy
  18. Another JIT implementation: Numba from numba import autojit ! @autojit

    def sum2d(arr): M, N = arr.shape result = 0.0 for i in range(M): for j in range(N): result += arr[i,j] return result
  19. Cython - Python Compiler • http://cython.org/ • Compiles your python

    code to C • Allows you to put static type checking into python • Relatively easy to produce C speeds for simple problems • Loots of cooperation with numpy, can run numpy’s C backend natively
  20. Further Reading Watching • Alex Gaynor “Why Python, Ruby and

    Javascript are Slow” in Waza 2013 • http://vimeo.com/61044810 • Great talk about the same issues covered here, a bit in more detail. • Some of my material is heavily inspired by this talk.