Nikolaij
Nikolaij

Reputation: 321

Huge difference in process timing of functions (timit, time)

For some didactical purposes, I want to measure the timing of some functions (slightly more complex ones, than the ones shown) and discuss later on the big O scaling behaviour. But I have problems with the reliability of the numbers produced:

My code:

import time
import numpy as np

def run_time(fun, runs):
    times = []
    for i in range(runs):
        t0 = time.clock() 
        fun()
        t1 = time.clock() - t0
        times.append(t1)
    return np.mean(times), np.std(times)#, times


def fact0(n):
    product = 1
    for i in range(n):
        product = product * (i+1)
    return product

def fact1(n):
    if n == 0:
        return 1
    else:
        return n * fact1(n-1)

print(run_time(lambda: fact0(500), 100000))
print(run_time(lambda: fact1(500), 100000))

and I usually get something like:

(0.000186065330000082, 5.08689027009196e-05)
(0.0002853808799999845, 8.285739309454826e-05)

So the std larger than the mean. That's awful for me. Furthermore I expected fact0() to be way faster than fact1() due to no recursion.

If I now use timeit:

import timeit
mysetup = ""
mycode = ''' 
def fact1(n):
    if n == 0:
        return 1
    else:
        return n * fact1(n-1)

fact1(500)
'''
print(timeit.timeit(setup = mysetup, stmt = mycode, number = 100000)/100000)

I'll get something almost an order of magnt. smaller for mean:

2.463713497854769e-07

After the below discussed corrections it is:

0.00028513264190871266

Which is in great accordance to the run_time version.

So my question is how do I time functions appropriately? Why the huge difference between my two methods to get the timing? Any advices? I would love to stick to "time.clock()" and I don't want to use (again for didactical reasons) cProfile or even more complex modules.

I am grateful for any comments...

(edited due to comments by @Carcigenicate)

Upvotes: 1

Views: 167

Answers (1)

Carcigenicate
Carcigenicate

Reputation: 45806

You never call the function in mycode, so you're only timing how long it takes the function to be defined (which I would expect to be quite fast).

You need to call the function:

import timeit

mycode = ''' 
def fact1(n):
    if n == 0:
        return 1
    else:
        return n * fact1(n-1)

fact1(100000)
'''

print(timeit.timeit(stmt=mycode, number=100000) / 100000)

Really though, this is suboptimal, since you're including in the timing the definition. I'd change this up and just pass a function:

def fact1(n):
    if n == 0:
        return 1
    else:
        return n * fact1(n-1) 

print(timeit.timeit(lambda: fact1(100000), number=100000) / 100000)

Upvotes: 1

Related Questions