26
What I Know About Python Performance A. Jesse Jiryu Davis http://emptysqua.re MongoDB

Python Performance: Single-threaded, multi-threaded, and Gevent

Embed Size (px)

DESCRIPTION

A smatter of performance tips for Python programs.

Citation preview

Page 1: Python Performance: Single-threaded, multi-threaded, and Gevent

What I Know About Python Performance

A. Jesse Jiryu Davishttp://emptysqua.re

MongoDB

Page 2: Python Performance: Single-threaded, multi-threaded, and Gevent

Agenda

• Single-threaded

• Multi-threaded

• Gevent

Page 3: Python Performance: Single-threaded, multi-threaded, and Gevent

Single-Threaded

Why is Python slow? • Everything’s an object • Lookup

Page 4: Python Performance: Single-threaded, multi-threaded, and Gevent

Everything’s an object

def f():! i = 2000! i += 1!

Page 5: Python Performance: Single-threaded, multi-threaded, and Gevent

Everything’s an object

import dis!dis.dis(f)!

Page 6: Python Performance: Single-threaded, multi-threaded, and Gevent

Everything’s an object

0 LOAD_CONST 1 (2000)! 3 STORE_FAST 0 (i)! 6 LOAD_FAST 0 (i)! 9 LOAD_CONST 2 (1)!12 INPLACE_ADD!13 STORE_FAST 0 (i)!

def f():! i = 2000! i += 1

Page 7: Python Performance: Single-threaded, multi-threaded, and Gevent

Everything’s an object

0 LOAD_CONST 1 (2000)! 3 STORE_FAST 0 (i)! 6 LOAD_FAST 0 (i)! 9 LOAD_CONST 2 (1)!12 INPLACE_ADD!13 STORE_FAST 0 (i)!

malloc!

malloc!

def f():! i = 2000! i += 1

Page 8: Python Performance: Single-threaded, multi-threaded, and Gevent

Everything’s an object

12 seconds for 100M numbers:

total = 0!for i in longs:! total += i!print float(total) / len(longs)

Page 9: Python Performance: Single-threaded, multi-threaded, and Gevent

Everything’s an object

1 second for 100M numbers:

print float(sum(longs)) / len(longs)

Page 10: Python Performance: Single-threaded, multi-threaded, and Gevent

Everything’s an object

0.2 seconds for 100M numbers:

print numpy.mean(array)

Page 11: Python Performance: Single-threaded, multi-threaded, and Gevent

Lookup

n = 1!!

def f():! print n!

Page 12: Python Performance: Single-threaded, multi-threaded, and Gevent

0 LOAD_GLOBAL 0 (n)! 3 PRINT_ITEM! 4 PRINT_NEWLINE

hashtable lookup

n = 1!!

def f():! print n!

Page 13: Python Performance: Single-threaded, multi-threaded, and Gevent

array offset

n = 1!!

def f(n=n):! print n!

0 LOAD_FAST 0 (n)! 3 PRINT_ITEM! 4 PRINT_NEWLINE

Page 14: Python Performance: Single-threaded, multi-threaded, and Gevent

Profiling

Page 15: Python Performance: Single-threaded, multi-threaded, and Gevent

Profiling

import yappi!!yappi.start(builtins=True)!my_function()!yappi.stop()!stats = yappi.get_func_stats()!stats.save('yappi.callgrind', type='callgrind')!

Page 16: Python Performance: Single-threaded, multi-threaded, and Gevent

KCacheGrind

Page 17: Python Performance: Single-threaded, multi-threaded, and Gevent

KCacheGrind

Page 18: Python Performance: Single-threaded, multi-threaded, and Gevent

Multi-threaded

Page 19: Python Performance: Single-threaded, multi-threaded, and Gevent

Multi-threaded

When is the GIL released?• Every 100 bytecodes• Acquiring other locks • Network or file operations

Page 20: Python Performance: Single-threaded, multi-threaded, and Gevent

Multi-threadedBecause:

socketmodule.c

Py_BEGIN_ALLOW_THREADS!outlen = recv(s->sock_fd, cbuf, len);!Py_END_ALLOW_THREADS!

Page 21: Python Performance: Single-threaded, multi-threaded, and Gevent

Multi-threadedBecause:

socketmodule.c

Py_BEGIN_ALLOW_THREADS!outlen = recv(s->sock_fd, cbuf, len);!Py_END_ALLOW_THREADS!

release the GIL!

Page 22: Python Performance: Single-threaded, multi-threaded, and Gevent

Multi-threadedThis makes sense:

threads = [! threading.Thread(target=download_a_url())! for _ in range(10)]!!for t in threads:! t.start()!!for t in threads:! t.join()!

Page 23: Python Performance: Single-threaded, multi-threaded, and Gevent

Multi-threadedThis makes no sense:

threads = [! threading.Thread(target=do_calculations())! for _ in range(10)]!!for t in threads:! t.start()!!for t in threads:! t.join()!

Page 24: Python Performance: Single-threaded, multi-threaded, and Gevent

Geventfrom gevent import monkey!monkey.patch_all()!!threads = [! threading.Thread(target=download_a_url())]!!for t in threads:! t.start()!!for t in threads:! t.join()! actually a greenlet

Page 25: Python Performance: Single-threaded, multi-threaded, and Gevent

GreenletProfiler

Page 26: Python Performance: Single-threaded, multi-threaded, and Gevent

Links

http://bit.ly/pythonperformance