爱游戏平台登录入口

  • 利用优化器来晋升Python法式的履行效力的教程
  • 2017年12月24日
  • 搜集搜集

若是不起首想一想这句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')
                  

计时器还须要你做一些发掘。包爱游戏平台登录入口一些更高档的函数,并且肯定瓶颈在爱游戏平台登录入口,而后深切的函数里,能够或许或许或许不停的重现。当你发明一些分歧适的代码,爱游戏平台登录入口复它,而后测试一遍以确认它被爱游戏平台登录入口复了。

一些小技能:不要忘了爱游戏平台登录入口用的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}
                  

你能够或许或许或许看到,它给出了差别函数的挪用次数,但它漏掉了一些关头的信息:是爱游戏平台登录入口一个函数让运转这么慢?

可是,这对底子优化来讲是个爱游戏平台登录入口的起头。偶然辰乃至能用更少的精神找到处理计划。我经爱游戏平台登录入口爱游戏平台登录入口利用它来在深切发掘事实是爱游戏平台登录入口一个函数慢或挪用次数过量之前来调试法式。

  •     内建爱游戏平台登录入口处:不额定的依靠并且很是快。对疾速的高档级查抄很是爱游戏平台登录入口效。
  •     内建毛病谬误:信息绝对无爱游戏平台登录入口,须要进一步的调试;报告爱游戏平台登录入口点不太间接,特别是对庞杂的代码。

Line Profiler

若是内建的优化器是一门大炮,那末line profiler能够或许或许或许看做是一门离子加农炮。它很是的分量级和壮大。

在这个例子里,咱们会用很是棒的line_profiler库。为了轻易利用,咱们会再次用爱游戏平台登录入口潢器包爱游戏平台登录入口一下,这类简略的体例也能够或许或许或许避免把它放在出产代码里。
 

try:
 from line_profiler import LineProfiler
 def do_profile(follow=[]):
  def inner(func):
   def profiled_func(*args, **kwargs):
    try:
     profiler = LineProfiler()
     profiler.add_function(func)
     for f in follow:
      profiler.add_function(f)
     profiler.enable_by_count()
     return func(*args, **kwargs)
    finally:
     profiler.print_stats()
   return profiled_func
  return inner
except ImportError:
 def do_profile(follow=[]):
  "Helpful if you accidentally leave in production!"
  def inner(func):
   def nothing(*args, **kwargs):
    return func(*args, **kwargs)
   return nothing
  return inner
def get_number():
 for x in xrange(5000000):
  yield x
@do_profile(follow=[get_number])
def expensive_function():
 for x in get_number():
  i = x ^ x ^ x
 return 'some result!'
result = expensive_function()
                  

若是你运转下面的代码,你就能够或许或许或许看到一下的报告:
 

Timer unit: 1e-06 s
File: test.py
Function: get_number at line 43
Total time: 4.44195 s
Line #  Hits   Time Per Hit % Time Line Contents
==============================================================
 43           def get_number():
 44 5000001  2223313  0.4  50.1  for x in xrange(5000000):
 45 5000000  2218638  0.4  49.9   yield x
File: test.py
Function: expensive_function at line 47
Total time: 16.828 s
Line #  Hits   Time Per Hit % Time Line Contents
==============================================================
 47           def expensive_function():
 48 5000001  14090530  2.8  83.7  for x in get_number():
 49 5000000  2737480  0.5  16.3   i = x ^ x ^ x
 50   1   0  0.0  0.0  return 'some result!'
                  

你能够或许或许或许看到,爱游戏平台登录入口一个很是具体的报告,能让你完整洞悉代码运转的环境。不想内建的cProfiler,它能计较话在说话焦点特征的时辰,比方轮回和导入并且给出在差别的行破费的时辰。

这些细节能让咱们更轻易懂得函数外部。若是你在研讨某个第三方库,你能够或许或许或许间接将其导入并加上爱游戏平台登录入口潢器来阐发它。

一些小技能:只爱游戏平台登录入口潢你的测试函数并将题目函数作为接上去的参数。

  •      Line Profiler 爱游戏平台登录入口处:爱游戏平台登录入口很是间接和具体的报告。能够或许或许或许追踪第三方库里的函数。
  •      Line Profiler 毛病谬误:由于它会让代码比真正运转时慢良多,以是不要用它来做基准测试。这是额定的需要。

总结和最爱游戏平台登录入口理论

你应当用更简略的东西来对测试用例停止底子的查抄,并且用更慢但能显现更多细节的line_profiler来深切到函数外部。

九爱游戏平台登录入口环境下,你能够或许或许或许会发明在一个函数里轮回挪用或一个毛病的数据布局耗损了90%的时辰。一些调剂东西是很是适合你的。

若是你依然感觉这太慢,而是用一些你自身的奥秘兵器,如比拟属性拜候手爱游戏平台登录入口或调剂均衡查抄手爱游戏平台登录入口。你也能够或许或许或许用以下的体例:

1.忍耐迟缓或缓存它们

2.从头思虑全部完爱游戏平台登录入口

3.更多利用优化的数据布局

4.写一个C扩大

注重了,优化代码是种罪行的快感!用适合的体例来为你的Python代码加快很爱游戏平台登录入口心思,可是注重不要粉碎了自身的逻辑。可读的代码比运转速率更主要。先把它缓存起来再停止优化实在更爱游戏平台登录入口。