mike watkins dot ca : Python 3 Performance: A Red Herring?

Python 3 Performance: A Red Herring?

This entry was split from an overly long journal entry entitled Why Python 3?

I was once guilty of dwelling on raw language performance, but no longer. For the work I do, developer productivity is much more important than raw language speed. It doesn't trouble me at all that Python 3 is a little slower than the most recent 2.x release we have in production (2.5). History has shown the Python developer group are rather good at optimizing Python under the hood, so now that the language implementation has stabilized, we can look forward to plenty of optimizations coming to the 3 branch in time.

Yet Python 3 today is no slouch. For the work I do -- web application development -- I'm finding the first release of Python 3 performs roughly equivalent to Python 2.5.x, and that matters more to me than pystone or some other abstract measure.

Benchmark 1: pystone

Speaking of pystone, here is how this old single processor Unix workstation I'm using stacks up:

$ python2.5 /usr/local/lib/python2.5/test/pystone.py
Pystone(1.1) time for 50000 passes = 1.75781
This machine benchmarks at 28444.4 pystones/second

$ python2.6 /usr/local/lib/python2.6/test/pystone.py
Pystone(1.1) time for 50000 passes = 1.46094
This machine benchmarks at 34224.6 pystones/second

$ python3.0 /usr/local/lib/python3.0/test/pystone.py
Pystone(1.1) time for 50000 passes = 1.85938
This machine benchmarks at 26890.8 pystones/second

Benchmark 2: web app

Here is an obligatory (yet crude) web application benchmark - retrieving a wiki page - on the same old machine while gvim and a bunch of other stuff is also running:

ab -n 1000 http://127.0.0.1:8002/qwiki/foo/

             Req/second
Python 2.5   174.79
Python 2.6   204.29
Python 3.0   173.49

Benchmark 3: web framework template

The following benchmark was based off a templating benchmark included in the Genshi package and utilizes Python's timeit module, averaging 10 passes creating a large html table using the following Qpy template:

# this is to provide a Qpy template for use in comparison
# with the Genshi "bigtable" benchmark.

table = [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10)
          for x in range(1000)]

def qpy_template:xml():
    '<table>'
    for row in table:
        '<tr>'
        for col in row.values():
            '<td>%s</td>' % col
        '</tr>'
    '</table>'

You can see that Qpy isn't the only package to benefit from the improved performance in Python 2.6 and Python 3.0, and I'm sure we'll see need for speed type coptimization efforts in due course to bring some modules back to where they were:

$ python2.5 bigtable.py
ElementTree                         736.43 ms
cStringIO                            36.46 ms
StringIO                            141.10 ms
list concat                          22.73 ms
Qpy Template                        129.35 ms

$ python2.6 bigtable.py
ElementTree                         656.99 ms
cStringIO                            30.85 ms
StringIO                            131.95 ms
list concat                          16.37 ms
Qpy Template                         39.54 ms

$ python3.0 bigtable.py
ElementTree                         449.60 ms
StringIO                            138.03 ms
list concat                          21.70 ms
Qpy Template                         36.36 ms

Conclusion: There are valid reasons why one might choose Python 2.x today over Python 3.0, but raw performance is not likely to be one of them for many developers.