如何使用timeit模块

我理解什么时间的概念,但我不知道如何在我的代码中实现它。

我怎样才能比较两个函数,说tim_sorttim_sorttimeit

timeit工作的方式是运行一次设置代码,然后重复调用一系列语句。 所以,如果你想testingsorting,需要注意一点,这样一次就地sorting就不会影响已经sorting的数据的下一个传递(当然,这会使Timsort真正发光,因为它performance最好当数据已经部分sorting)。

这里是一个如何设置sortingtesting的例子:

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

请注意,这一系列的陈述在每一次传递中都会对未sorting的数据进行全新的复制。

另外,请注意运行测量套件七次并保持最佳时间的计时技术 – 这可以真正帮助减less由于系统上运行的其他进程而导致的测量失真。

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

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

  1. 使用IPython shell。 它具有方便的%timeit特殊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 
  2. 在一个标准的Python解释器中,你可以通过在setup语句中的__main__中导入它们来访问在交互式会话中定义的函数和其他名称:

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

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

在命令行上, timeit做了适当的统计分析:它告诉你最短的运行时间。 这很好,因为所有的时间错误都是正面的。 所以最短的时间是最less的。 没有办法得到负面的错误,因为计算机不能计算得比计算得更快!

所以,命令行界面:

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

如果你想要有更长的脚本,你可能会试图在Python脚本中移动。 我build议避免这种情况,因为分析和时间在命令行上是更好的。 相反,我倾向于使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创build的timeit环境中的主模块中的代码。

值得注意的是,这是Timer(...).timeit(...)一个简便包装,因此在时序方面并不是特别好。 我个人更喜欢使用Timer如上所示。


警告

有几个警告随处可见。

  • 开销不计算在内。 假设你想要时间x += 1 ,找出添加需要多长时间:

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

    那么,这不是 0.0476微秒。 你只知道它比这less 。 所有的错误是积极的。

    所以试着find纯粹的开销:

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

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

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

如果你想快速比较两个代码/函数块,你可以这样做:

 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) 

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

鉴于test.py

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

运行timeit像这样:

 % python -mtimeit -s'import test' 'test.InsertionSort()' % python -mtimeit -s'import test' 'test.TimSort()' 
 # Генерация целых чисел 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) 

可以在下面的每一个中设置相同的字典并testing执行时间。

设置参数基本上是设置字典

编号是运行代码1000000次。 不是设置,而是stmt

当你运行这个时,你可以看到索引比得到的速度快。 您可以多次运行以查看。

代码基本上试图获得字典中的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

这很好用:

  python -m timeit -c "$(cat file_name.py)" 

内置的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 

如何使用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 

只需传递整个代码作为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))