• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >python > 使用优化器来提升Python程序的执行效率的教程

使用优化器来提升Python程序的执行效率的教程

作者: 字体:[增加 减小] 来源:互联网

通过本文主要向大家介绍了python 执行效率,python 效率,python 提高效率,python 运行效率,python 效率 大文件等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

如果不首先想想这句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()

</div>

当然,你可以用上下文管理来让它功能更加强大,添加一些检查点或者一些其他的功能:
 

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')
</div>

计时器还需要你做一些挖掘。包装一些更高级的函数,并且确定瓶颈在哪,然后深入的函数里,能够不停的重现。当你发现一些不合适的代码,修复它,然后测试一遍以确认它被修复了。

一些小技巧:不要忘了好用的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()
</div>

在上面代码的情况下,你应该看到有些东西在终端打印出来,打印的内容如下:
 

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}
</div>

你可以看到,它给出了不同函数的调用次数,但它遗漏了一些关键的信息:是哪个函数让运行这么慢?

可是,这对于基础优化来说是个好的开始。有时候甚至能用更少的精力找到解决方案。我经常用它来在深入挖掘究竟是哪个函数慢或者调用次数过多之前来调试程序。

  •     内建优点:没有额外的依赖并且非常快。对于快速的高等级检查非常有用。
  •     内建缺点:信息相对有限,需要进一步的调试;报告有点不太直接,尤其是对于复杂的代码。

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()
</div>

如果你运行上面的代码,你就可以看到一下的报告:
 

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!'
</div>

你可以看到,有一个非常详细的报告,能让你完全洞悉代码运行的情况。不想内建的cProfiler,它能计算话在语言核心特性的时间,比如循环和导入并且给出在不同的行花费的时间。

这些细节能让我们更容易理解函数内部。如果你在研究某个第三方库,你可以直接将其导入并加上装饰器来分析它。

一些小技巧:只装饰你的测试函数并将问题函数作为接下来的参数。

  •      Line Profiler 优点:有非常直接和详细的报告。能够追踪第三方库里的函数。
  •      Line Profiler 缺点:因为它会让代码比真正运行时慢很多,所以不要用它来做基准测试。这是额外的需求。

总结和最佳实践

您可能想查找下面的文章:

  • 几个提升Python运行效率的方法之间的对比
  • 使用优化器来提升Python程序的执行效率的教程
  • 提升Python程序运行效率的6个方法
  • 盘点提高 Python 代码效率的方法

相关文章

  • Python 内置函数complex详解
  • 使用python检测主机存活端口及检查存活主机
  • Python使用lxml模块和Requests模块抓取HTML页面的教程
  • Python 读写文件和file对象的方法(推荐)
  • 利用numpy+matplotlib绘图的基本操作教程
  • Python的Tornado框架实现异步非阻塞访问数据库的示例
  • python脚本设置系统时间的两种方法
  • Python 的 with 语句详解
  • Django的session中对于用户验证的支持
  • 爬山算法简介和Python实现实例

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • Python使用chardet判断字符编码
    • 介绍Python的Django框架中的静态资源管理器django-pipeline
    • 在Mac OS系统上安装Python的Pillow库的教程
    • Python编写电话薄实现增删改查功能
    • python文件操作相关知识点总结整理
    • Python实现网络端口转发和重定向的方法
    • Python中的闭包实例详解
    • Python enumerate遍历数组示例应用
    • Python标准库urllib2的一些使用细节总结
    • Python实现视频下载功能

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有