423

我理解做什么的概念,timeit但我不确定如何在我的代码中实现它。

如何比较两个函数,比如insertion_sorttim_sort,与timeit

4

14 回答 14

318

如果要timeit在交互式 Python 会话中使用,有两个方便的选项:

  1. 使用IPython外壳。它具有方便的%timeit特殊功能:

    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
    
  2. 在标准 Python 解释器中,您可以通过__main__在 setup 语句中导入它们来访问之前在交互式会话期间定义的函数和其他名称:

    >>> 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]
    
于 2011-11-22T01:41:48.890 回答
308

timeit的工作方式是运行一次设置代码,然后重复调用一系列语句。所以,如果你想测试排序,需要注意一下,这样就地排序的一次通过不会影响已经排序的数据的下一次通过(当然,这会使Timsort真正闪耀,因为它表现最好当数据已经部分排序时)。

以下是如何设置排序测试的示例:

>>> 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

请注意,这一系列语句在每次传递时都会生成未排序数据的新副本。

另外,请注意运行测量套件七次并只保留最佳时间的计时技术——这确实有助于减少由于系统上运行的其他进程导致的测量失真。

这些是我正确使用 timeit 的技巧。希望这可以帮助 :-)

于 2011-11-22T01:38:10.127 回答
162

我要告诉你一个秘密:最好的使用方式timeit是在命令行上。

在命令行上,timeit进行适当的统计分析:它告诉你最短的运行用了多长时间。这很好,因为时间上的所有错误都是积极的。所以最短的时间误差最小。没有办法得到负错误,因为计算机的计算速度永远不会超过它的计算速度!

所以,命令行界面:

%~> python -m timeit "1 + 2"
10000000 loops, best of 3: 0.0468 usec per loop

这很简单,嗯?

你可以设置东西:

%~> python -m timeit -s "x = range(10000)" "sum(x)"
1000 loops, best of 3: 543 usec per loop

这也很有用!

如果你想要多行,你可以使用 shell 的自动延续或使用单独的参数:

%~> python -m timeit -s "x = range(10000)" -s "y = range(100)" "sum(x)" "min(y)"
1000 loops, best of 3: 554 usec per loop

这给出了一个设置

x = range(1000)
y = range(100)

和时代

sum(x)
min(y)

如果您想拥有更长的脚本,您可能会倾向于移至timeitPython 脚本内部。我建议避免这种情况,因为在命令行上的分析和时间安排更好。相反,我倾向于制作 shell 脚本:

 SETUP="

 ... # lots of stuff

 "

 echo Minmod arr1
 python -m timeit -s "$SETUP" "Minmod(arr1)"

 echo pure_minmod arr1
 python -m timeit -s "$SETUP" "pure_minmod(arr1)"

 echo better_minmod arr1
 python -m timeit -s "$SETUP" "better_minmod(arr1)"

 ... etc

由于多次初始化,这可能需要更长的时间,但通常这没什么大不了的。


但是如果你timeit在你的模块中使用呢?

好吧,简单的方法是:

def function(...):
    ...

timeit.Timer(function).timeit(number=NUMBER)

这给了你累积的(不是最少的!)时间来运行那个次数。

要获得良好的分析,请使用.repeat并取最小值:

min(timeit.Timer(function).repeat(repeat=REPEATS, number=NUMBER))

您通常应该将其与functools.partial而不是结合使用lambda: ...以降低开销。因此你可以有类似的东西:

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

你也可以这样做:

timeit.timeit("...", setup="from __main__ import ...", number=NUMBER)

这将使您从命令行更接近界面,但以一种不那么酷的方式。允许您在"from __main__ import ..."timeit.

值得注意的是,这是一个方便的包装器Timer(...).timeit(...),因此并不是特别擅长计时。我个人更喜欢使用Timer(...).repeat(...)如上所示。


警告

timeit到处都有一些警告。

  • 间接费用不计入。假设你想 time x += 1,找出加法需要多长时间:

    >>> python -m timeit -s "x = 0" "x += 1"
    10000000 loops, best of 3: 0.0476 usec per loop
    

    嗯,它不是0.0476 µs。你只知道它比这。所有错误都是正面的。

    所以试着找到纯粹的开销:

    >>> python -m timeit -s "x = 0" ""      
    100000000 loops, best of 3: 0.014 usec per loop
    

    仅从时间来看,这是一个很好的30%开销!这会极大地扭曲相对时间。但是您只真正关心添加时间;的查找时间x也需要包含在开销中:

    >>> python -m timeit -s "x = 0" "x"
    100000000 loops, best of 3: 0.0166 usec per loop
    

    差异不是很大,但它就在那里。

  • 变异方法是危险的。

    >>> python -m timeit -s "x = [0]*100000" "while x: x.pop()"
    10000000 loops, best of 3: 0.0436 usec per loop
    

    但这是完全错误的! x是第一次迭代后的空列表。您需要重新初始化:

    >>> python -m timeit "x = [0]*100000" "while x: x.pop()"
    100 loops, best of 3: 9.79 msec per loop
    

    但是你有很多开销。单独考虑。

    >>> python -m timeit "x = [0]*100000"                   
    1000 loops, best of 3: 261 usec per loop
    

    请注意,这里减去开销是合理的,因为开销只是时间的一小部分。

    对于您的示例,值得注意的是,对于已排序的列表,插入排序和 Tim 排序都具有完全不寻常的计时行为。random.shuffle这意味着如果你想避免破坏你的时间,你将需要一个between sorts。

于 2014-06-08T11:51:43.610 回答
118

如果您想快速比较两个代码/功能块,您可以这样做:

import timeit

start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)
于 2015-04-08T10:33:05.513 回答
48

我发现使用 timeit 的最简单方法是从命令行:

给定test.py

def InsertionSort(): ...
def TimSort(): ...

像这样运行timeit:

% python -mtimeit -s'import test' 'test.InsertionSort()'
% python -mtimeit -s'import test' 'test.TimSort()'
于 2011-11-22T01:28:22.947 回答
27

对我来说,这是最快的方法:

import timeit
def foo():
    print("here is my code to time...")


timeit.timeit(stmt=foo, number=1234567)
于 2018-01-17T13:49:51.240 回答
13
# Генерация целых чисел

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)
于 2017-04-01T22:31:07.417 回答
9

这很好用:

  python -m timeit -c "$(cat file_name.py)"
于 2017-07-21T00:33:56.567 回答
8

只需将整个代码作为 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))
于 2017-10-04T19:30:13.690 回答
4

让我们在以下每个中设置相同的字典并测试执行时间。

setup 参数基本上是设置字典

Number 是运行代码 1000000 次。不是设置而是stmt

当你运行它时,你可以看到 index 比 get 快得多。您可以多次运行它来查看。

该代码基本上试图在字典中获取 c 的值。

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))

这是我的结果,你的会有所不同。

按索引:0.20900007452246427

通过获取:0.54841166886888

于 2016-09-26T15:31:21.647 回答
1

内置的 timeit 模块在 IPython 命令行中效果最好。

从模块内对函数计时:

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
于 2017-06-05T23:40:57.193 回答
1

如何将 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                                                                                        
于 2017-06-19T16:56:15.207 回答
1

您将创建两个函数,然后运行与此类似的东西。请注意,您要选择相同数量的执行/运行来比较苹果和苹果。
这是在 Python 3.7 下测试的。

在此处输入图像描述 这是便于复制的代码

!/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")
于 2018-09-12T23:17:13.470 回答
1
import timeit


def oct(x):
   return x*x


timeit.Timer("for x in range(100): oct(x)", "gc.enable()").timeit()
于 2019-02-07T13:50:21.963 回答