Tibor's Musings

Python Exception Handling Overhead

In a previous blog post, I've estimated Python OO method call overhead to be about 10% over function calls. What about exception handling?

Here the situation differs. Exceptions are so pervasive in Python core language that handling exceptional cases of your code via adding more exceptions do not add much overhead at all. Here is a simple brute-force comparison of returning C-style (res, err, wrn) tuples versus returning res and exceptions:

"""
Measure the speed of exception handling mechanism in Python, by
comparing returning of (res, err, wrn) tuples to returning res only
with raising exceptions.

Results run on PCUDS17 on 2006-06-13 are:

$ python2.3 exception_handling_speed.py
testing speed of exception handling versus returning (res, err, wrn) tuples:
f_tuples() returning never errors ........ 1.700 sec
f_exception() returning never errors ..... 1.000 sec
f_tuples() returning always errors ....... 1.580 sec
f_exception() returning always errors .... 3.940 sec
"""

m = 10000

class MyError(Exception):
    pass

def f_tuples_slave(n,okay=1):
    """Do some calculations and return res, err, wrn tuple."""
    if okay:
        return n*n, [], []
    else:
        return 0, ['foo'], ['bar']

def f_exceptions_slave(n,okay=1):
    """Do some calculations and return res plus raise exception."""
    if okay:
        return n*n
    else:
        raise MyError

def f_tuples(okay=1):
    global m
    x = 0
    for i in range(0,m):
        res, err, wrn = f_tuples_slave(i, okay)
        if err == []:
            x += res
    return x

def f_exceptions(okay=1):
    global m
    x = 0
    for i in range(0,m):
        try:
            x += f_exceptions_slave(i, okay)
        except MyError:
            pass
    return x

import time
def timing(f, a, n=10):
    """Return timing of function F on argument A run N times.
       Taken from <http://www.python.org/doc/essays/list2str.html>.
    """
    r = range(n)
    t1 = time.clock()
    for i in r:
        f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a)
    t2 = time.clock()
    return round(t2-t1, 3)

def main():
    """Demonstrate the memoization technique for the Fibonacci calculator."""
    print "testing speed of exception handling versus returning (res, err, wrn) tuples:"
    # test returning 0% exceptions case:
    time = timing(f_tuples, 1)
    print "f_tuples() returning never errors ........ %.3f sec" % time
    time = timing(f_exceptions, 1)
    print "f_exception() returning never errors ..... %.3f sec" % time
    # test returning 100% exceptions case:
    time = timing(f_tuples, 0)
    print "f_tuples() returning always errors ....... %.3f sec" % time
    time = timing(f_exceptions, 0)
    print "f_exception() returning always errors .... %.3f sec" % time
    return

if __name__ == '__main__':
    main()

python