优化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    @timefuncdef 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_cprofiledef 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 43Total 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 47Total 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代码加速很有意思,但是注意不要破坏了本身的逻辑。可读的代码比运行速度更重要。先把它缓存起来再进行优化其实更好。

时间: 2024-07-29 22:46:12

优化python执行效率的相关文章

提高python执行效率的方法

python上手很容易,但是在使用过程中,怎么才能使效率变高呢? 下面说一下提高python执行效率的方法,这里只是说一点,python在引入模块过程中提高效率的方法. 例如: 1.我们要使用os模块中的某个属性,那我们可以单独引入os中某个属性 from os import version 同样的我们也可以把引入的模块属性或者对象,直接赋给另外一个变量,使用as方法 from os import version as ver 这样使用方便 2.如果在一个函数中频繁的使用某个模块的属性,那我们可

Ansible之优化提升执行效率

今天分享一下Ansible在工作环境中有那些可以优化的配置 环境介绍:以前在公司工作处理服务器问题,需要用批量操作都是用shell脚本编写的工具,后来发现Ansible这个自动化工具,安装简单,操作起来很方便,支持多个模块,由python开发基于SSH协议通信的工具.这里有个问题就是如果服务器越来越多,Ansibe执行效率会变得比较慢,可以通过优化Ansible提供工作效率,具体优化的方法如下: 线上管理机器:操作系统Linux,cpu为4核,内存8G,用这个机器管理上千台Linux服务器都没有

SQL Server SQL性能优化之--通过拆分SQL提高执行效率,以及性能高低背后的原因

复杂SQL拆分优化 拆分SQL是性能优化一种非常有效的方法之一, 具体就是将复杂的SQL按照一定的逻辑逐步分解成简单的SQL,借助临时表,最后执行一个等价的逻辑,已达到高效执行的目的 一直想写一遍通过拆分SQL来优化的博文,最近刚好遇到一个实际案例,比较有代表性,现分享出来, 我们来通过一个案例来分析,为什么拆分语句可以提高SQL执行效率,更重要的是弄清楚,拆分前为什么慢,拆分后为什么快了? 幼稚的话,各位看官莫笑 先看一下相关表的数据量,大表也有5900多万,小表有160多万 (声明:我从来没

PHP对接口执行效率慢的优化

PHP对接口执行效率慢的优化 造成执行效率低的原因可以由很多方面找原因 从代码层面,代码质量低,执行效率也会有很大影响的. 从硬件方面,服务器配置低,服务器配置是基础,这个跑不动肯定慢. 从数据量方面,查询数据量过多,sql语句过于繁杂,执行缓慢. 服务器 从配置上做提升,对于系统整体的执行效率是相当明显的,这一点没有什么好质疑的,只要有实力,自然就可以多在这方面做提升了. 数据查询 这个查询的优化,涉及sql的优化,或者到数据库的优化,下面有几个简单的优化方案. sql的优化,适当使用链表查询

关于提高python程序执行效率的思路和想法

相比编译型语言(C系列)python胜在简介的语法和优雅的动态编程体验,但是在执行效率上,python有解释性语言先天的劣势——执行效率较低,为了让编写出的程序获得更快的执行效率,开启此文章. python将编写好的程序源代码转为字节码,然后用PVM进行解释执行. 方法一:对代码进行优化 循环体中避免无用的赋值和计算,这在所用的编程中是通用的,而且效果显著. 第三方库的选择,比如对于html文本处理,正确使用 re 的解析速度显然会高于BeautifulSoup. 方法二:使用编译优化工具 Py

使用Android的硬件缩放技术优化执行效率

Unity3D研究院之使用Android的硬件缩放技术优化执行效率 http://www.xuanyusong.com/archives/3205 Android中GLSurfaceView在横竖屏切换时重新创建表面缓冲导致的问题 http://blog.k-res.net/archives/1702.html https://stackoverflow.com/questions/7185644/android-opengl-crazy-aspect-ratio-after-sleep

SQL Server 并行操作优化,避免并行操作被抑制而影响SQL的执行效率

为什么我也要说SQL Server的并行: 这几天园子里写关于SQL Server并行的文章很多,不管怎么样,都让人对并行操作有了更深刻的认识. 我想说的是:尽管并行操作可能(并不是一定)存在这样或者那样的问题,但是我们不能否认并行,仍然要利用好并行. 但是,实际开发中,某些SQL语句的写法会导致用不到并行,从而影响到SQL的执行效率 所以,本文要表达的是:我们要利用好并行,不要让一些SQL的写法问题“抑制”了并行,让我们享受不了并行带来的快感 关于SQL Server的并行: 所谓的并行,指S

mysql优化(三)–explain分析sql语句执行效率

mysql优化(三)–explain分析sql语句执行效率 mushu 发布于 11个月前 (06-04) 分类:Mysql 阅读(651) 评论(0) Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优化语句. Explain语法:explain select … from … [where …] 例如:explain select * from

Linq的执行效率及优化

描述:项目中使用了linq,发现写的顺序不一样最后的结果也不一样,效率也不一样. Linq的执行效率对比 List<int> source = new List<int>(); var rand = new Random(); int i = 5000; while (i > 0) { i--; source.Add(rand.Next(1, 500)); } Stopwatch watch = new Stopwatch(); watch.Restart(); var te