>>>import timeit
>>> setup ='''
import random
random.seed('slartibartfast')
s = [random.random() for i in range(1000)]
timsort = list.sort
'''>>>print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7,1000))0.334147930145
The way timeit works is to run setup code once and then make repeated calls to a series of statements. So, if you want to test sorting, some care is required so that one pass at an in-place sort doesn’t affect the next pass with already sorted data (that, of course, would make the Timsort really shine because it performs best when the data already partially ordered).
Here is an example of how to set up a test for sorting:
>>> import timeit
>>> setup = '''
import random
random.seed('slartibartfast')
s = [random.random() for i in range(1000)]
timsort = list.sort
'''
>>> print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7, 1000))
0.334147930145
Note that the series of statements makes a fresh copy of the unsorted data on every pass.
Also, note the timing technique of running the measurement suite seven times and keeping only the best time — this can really help reduce measurement distortions due to other processes running on your system.
Those are my tips for using timeit correctly. Hope this helps :-)
>>>def f(x):...return x * x
...>>>import timeit
>>> timeit.repeat("for x in range(100): f(x)","from __main__ import f",
number=100000)[2.0640320777893066,2.0876040458679199,2.0520210266113281]
If you want to use timeit in an interactive Python session, there are two convenient options:
Use the IPython shell. It features the convenient %timeit special function:
In [1]: def f(x):
...: return x*x
...:
In [2]: %timeit for x in range(100): f(x)
100000 loops, best of 3: 20.3 us per loop
In a standard Python interpreter, you can access functions and other names you defined earlier during the interactive session by importing them from __main__ in the setup statement:
>>> def f(x):
... return x * x
...
>>> import timeit
>>> timeit.repeat("for x in range(100): f(x)", "from __main__ import f",
number=100000)
[2.0640320777893066, 2.0876040458679199, 2.0520210266113281]
from functools import partial
def to_time(items):...
test_items =[1,2,3]*100
times = timeit.Timer(partial(to_time, test_items)).repeat(3,1000)# Divide by the number of repeats
time_taken = min(times)/1000
I’ll let you in on a secret: the best way to use timeit is on the command line.
On the command line, timeit does proper statistical analysis: it tells you how long the shortest run took. This is good because all error in timing is positive. So the shortest time has the least error in it. There’s no way to get negative error because a computer can’t ever compute faster than it can compute!
So, the command-line interface:
%~> python -m timeit "1 + 2"
10000000 loops, best of 3: 0.0468 usec per loop
That’s quite simple, eh?
You can set stuff up:
%~> python -m timeit -s "x = range(10000)" "sum(x)"
1000 loops, best of 3: 543 usec per loop
which is useful, too!
If you want multiple lines, you can either use the shell’s automatic continuation or use separate arguments:
%~> python -m timeit -s "x = range(10000)" -s "y = range(100)" "sum(x)" "min(y)"
1000 loops, best of 3: 554 usec per loop
That gives a setup of
x = range(1000)
y = range(100)
and times
sum(x)
min(y)
If you want to have longer scripts you might be tempted to move to timeit inside a Python script. I suggest avoiding that because the analysis and timing is simply better on the command line. Instead, I tend to make shell scripts:
which would give you something closer to the interface from the command-line, but in a much less cool manner. The "from __main__ import ..." lets you use code from your main module inside the artificial environment created by timeit.
It’s worth noting that this is a convenience wrapper for Timer(...).timeit(...) and so isn’t particularly good at timing. I personally far prefer using Timer(...).repeat(...) as I’ve shown above.
Warnings
There are a few caveats with timeit that hold everywhere.
Overhead is not accounted for. Say you want to time x += 1, to find out how long addition takes:
>>> python -m timeit -s "x = 0" "x += 1"
10000000 loops, best of 3: 0.0476 usec per loop
Well, it’s not 0.0476 µs. You only know that it’s less than that. All error is positive.
So try and find pure overhead:
>>> python -m timeit -s "x = 0" ""
100000000 loops, best of 3: 0.014 usec per loop
That’s a good 30% overhead just from timing! This can massively skew relative timings. But you only really cared about the adding timings; the look-up timings for x also need to be included in overhead:
>>> python -m timeit -s "x = 0" "x"
100000000 loops, best of 3: 0.0166 usec per loop
The difference isn’t much larger, but it’s there.
Mutating methods are dangerous.
>>> python -m timeit -s "x = [0]*100000" "while x: x.pop()"
10000000 loops, best of 3: 0.0436 usec per loop
But that’s completely wrong!x is the empty list after the first iteration. You’ll need to reinitialize:
>>> python -m timeit "x = [0]*100000" "while x: x.pop()"
100 loops, best of 3: 9.79 msec per loop
But then you have lots of overhead. Account for that separately.
>>> python -m timeit "x = [0]*100000"
1000 loops, best of 3: 261 usec per loop
Note that subtracting the overhead is reasonable here only because the overhead is a small-ish fraction of the time.
For your example, it’s worth noting that both Insertion Sort and Tim Sort have completely unusual timing behaviours for already-sorted lists. This means you will require a random.shuffle between sorts if you want to avoid wrecking your timings.
# Генерация целых чисел
def gen_prime(x):
multiples = []
results = []
for i in range(2, x+1):
if i not in multiples:
results.append(i)
for j in range(i*i, x+1, i):
multiples.append(j)
return results
import timeit
# Засекаем время
start_time = timeit.default_timer()
gen_prime(3000)
print(timeit.default_timer() - start_time)
# start_time = timeit.default_timer()
# gen_prime(1001)
# print(timeit.default_timer() - start_time)
import timeit
print('Getting value of C by index:', timeit.timeit(stmt="mydict['c']", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))print('Getting value of C by get:', timeit.timeit(stmt="mydict.get('c')", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
lets setup the same dictionary in each of the following and test the execution time.
The setup argument is basically setting up the dictionary
Number is to run the code 1000000 times. Not the setup but the stmt
When you run this you can see that index is way faster than get. You can run it multiple times to see.
The code basically tries to get the value of c in the dictionary.
import timeit
print('Getting value of C by index:', timeit.timeit(stmt="mydict['c']", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
print('Getting value of C by get:', timeit.timeit(stmt="mydict.get('c')", setup="mydict={'a':5, 'b':6, 'c':7}", number=1000000))
Here are my results, yours will differ.
by index: 0.20900007452246427
by get: 0.54841166886888
回答 9
只需将整个代码作为timeit的参数传递:
import timeit
print(timeit.timeit("""
limit = 10000
prime_list = [i for i in range(2, limit+1)]
for prime in prime_list:
for elem in range(prime*2, max(prime_list)+1, prime):
if elem in prime_list:
prime_list.remove(elem)
""", number=10))
simply pass your entire code as an argument of timeit:
import timeit
print(timeit.timeit(
"""
limit = 10000
prime_list = [i for i in range(2, limit+1)]
for prime in prime_list:
for elem in range(prime*2, max(prime_list)+1, prime):
if elem in prime_list:
prime_list.remove(elem)
"""
, number=10))
回答 10
import timeit
def oct(x):return x*x
timeit.Timer("for x in range(100): oct(x)","gc.enable()").timeit()
The built-in timeit module works best from the IPython command line.
To time functions from within a module:
from timeit import default_timer as timer
import sys
def timefunc(func, *args, **kwargs):
"""Time a function.
args:
iterations=3
Usage example:
timeit(myfunc, 1, b=2)
"""
try:
iterations = kwargs.pop('iterations')
except KeyError:
iterations = 3
elapsed = sys.maxsize
for _ in range(iterations):
start = timer()
result = func(*args, **kwargs)
elapsed = min(timer() - start, elapsed)
print(('Best of {} {}(): {:.9f}'.format(iterations, func.__name__, elapsed)))
return result
回答 12
如何将Python REPL解释器与接受参数的函数一起使用的示例。
>>>import timeit
>>>def naive_func(x):... a =0...for i in range(a):... a += i
...return a
>>>def wrapper(func,*args,**kwargs):...def wrapper():...return func(*args,**kwargs)...return wrapper
>>> wrapped = wrapper(naive_func,1_000)>>> timeit.timeit(wrapped, number=1_000_000)0.4458435332577161
You would create two functions and then run something similar to this.
Notice, you want to choose the same number of execution/run to compare apple to apple.
This was tested under Python 3.7.
Here is the code for ease of copying it
!/usr/local/bin/python3
import timeit
def fibonacci(n):
"""
Returns the n-th Fibonacci number.
"""
if(n == 0):
result = 0
elif(n == 1):
result = 1
else:
result = fibonacci(n-1) + fibonacci(n-2)
return result
if __name__ == '__main__':
import timeit
t1 = timeit.Timer("fibonacci(13)", "from __main__ import fibonacci")
print("fibonacci ran:",t1.timeit(number=1000), "milliseconds")