我們應該忘掉一些小的效率問題,在 97% 的情況下是這麼說的:過早優化是萬惡之源。—— Donald Knuth
如果不首先想想這句Knuth的名言,就開始進行優化工作是不明智的。可是,你很快寫出來加入一些特性的代碼,可能會很丑陋,你需要注意了。這篇文章就是為這時候准備的。
那麼接下來就是一些很有用的工具和模式來快速優化Python。它的主要目的很簡單:盡快發現瓶頸,修復它們並且確認你修復了它們。
在你開始優化前,寫一個高級測試來證明原來代碼很慢。你可能需要采用一些最小值數據集來復現它足夠慢。通常一兩個顯示運行時秒的程序就足夠處理一些改進的地方了。
有一些基礎測試來保證你的優化沒有改變原有代碼的行為也是很必要的。你也能夠在很多次運行測試來優化代碼的時候稍微修改這些測試的基准。
那麼現在,我們來來看看優化工具把。
計時器很簡單,這是一個最靈活的記錄執行時間的方法。你可以把它放到任何地方並且副作用很小。運行你自己的計時器非常簡單,並且你可以將其定制,使它以你期望的方式工作。例如,你個簡單的計時器如下:
import time
def timefunc(f):
def f_timer(*args, **kwargs):
start = time.time()
result = f(*args, **kwargs)
end = time.time()
print f.__name__, 'took', end - start, 'time'
return result
return f_timer
def get_number():
for x in xrange(5000000):
yield x
@timefunc
def expensive_function():
for x in get_number():
i = x ^ x ^ x
return 'some result!'
# prints "expensive_function took 0.72583088875 seconds"
result = expensive_function()
當然,你可以用上下文管理來讓它功能更加強大,添加一些檢查點或者一些其他的功能:
import time
class timewith():
def __init__(self, name=''):
self.name = name
self.start = time.time()
@property
def elapsed(self):
return time.time() - self.start
def checkpoint(self, name=''):
print '{timer} {checkpoint} took {elapsed} seconds'.format(
timer=self.name,
checkpoint=name,
elapsed=self.elapsed,
).strip()
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.checkpoint('finished')
pass
def get_number():
for x in xrange(5000000):
yield x
def expensive_function():
for x in get_number():
i = x ^ x ^ x
return 'some result!'
# prints something like:
# fancy thing done with something took 0.582462072372 seconds
# fancy thing done with something else took 1.75355315208 seconds
# fancy thing finished took 1.7535982132 seconds
with timewith('fancy thing') as timer:
expensive_function()
timer.checkpoint('done with something')
expensive_function()
expensive_function()
timer.checkpoint('done with something else')
# or directly
timer = timewith('fancy thing')
expensive_function()
timer.checkpoint('done with something')