计时器还需要你做一些挖掘。包装一些更高级的函数,并且确定瓶颈在哪,然后深入的函数里,能够不停的重现。当你发现一些不合适的代码,修复它,然后测试一遍以确认它被修复了。
一些小技巧:不要忘了好用的timeit模块!它对小块代码做基准测试而不是实际调查更加有用。
Timer 优点:很容易理解和实现。也非常容易在修改后进行比较。对于很多语言都适用。
Timer 缺点:有时候对于非常复杂的代码有点过于简单,你可能会花更多时间放置或移动引用代码而不是修复问题!
内建优化器
启用内建的优化器就像是用一门大炮。它非常强大,但是有点不太好用,使用和解释起来比较复杂。
你可以了解更多关于profile模块的东西,但是它的基础是非常简单的:你能够启用和禁用优化器,而且它能打印所有的函数调用和执行时间。它能给你编译和打印出输出。一个简单的装饰器如下:
import cProfile
def do_cprofile(func):
def profiled_func(*args, **kwargs):
profile = cProfile.Profile()
try:
profile.enable()
result = func(*args, **kwargs)
profile.disable()
return result
finally:
profile.print_stats()
return profiled_func
def get_number():
for x in xrange(5000000):
yield x
@do_cprofile
def expensive_function():
for x in get_number():
i = x ^ x ^ x
return 'some result!'
# perform profiling
result = expensive_function()
在上面代码的情况下,你应该看到有些东西在终端打印出来,打印的内容如下:
5000003 function calls in 1.626 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
5000001 0.571 0.000 0.571 0.000 timers.py:92(get_number)
1 1.055 1.055 1.626 1.626 timers.py:96(expensive_function)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
你可以看到,它给出了不同函数的调用次数,但它遗漏了一些关键的信息:是哪个函数让运行这么慢?
可是,这对于基础优化来说是个好的开始。有时候甚至能用更少的精力找到解决方案。我经常用它来在深入挖掘究竟是哪个函数慢或者调用次数过多之前来调试程序。
内建优点:没有额外的依赖并且非常快。对于快速的高等级检查非常有用。
内建缺点:信息相对有限,需要进一步的调试;报告有点不太直接,尤其是对于复杂的代码。