龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > web编程 > python编程 >

深入理解Python 代码优化详解(4)

时间:2014-10-28 02:27来源:网络整理 作者:网络 点击:
分享到:
复制代码 代码如下: from timeit import Timer Timer("t=a;a=b;b=t","a=1;b=2").timeit() 0.25154118749729365 Timer("a,b=b,a","a=1;b=2").timeit() 0.17156677734181258 2、在循环的时候使用 xra

复制代码 代码如下:

>>> from timeit import Timer
 >>> Timer("t=a;a=b;b=t","a=1;b=2").timeit()
 0.25154118749729365
 >>> Timer("a,b=b,a","a=1;b=2").timeit()
 0.17156677734181258
 >>>

  2、在循环的时候使用 xrange 而不是 range;使用 xrange 可以节省大量的系统内存,因为 xrange() 在序列中每次调用只产生一个整数元素。而 range() 將直接返回完整的元素列表,用于循环时会有不必要的开销。在 python3 中 xrange 不再存在,里面 range 提供一个可以遍历任意长度的范围的 iterator。
 
  3、使用局部变量,避免”global” 关键字。python 访问局部变量会比全局变量要快得多,因 此可以利用这一特性提升性能。
 
  4、if done is not None 比语句 if done != None 更快,读者可以自行验证;
 
  5、在耗时较多的循环中,可以把函数的调用改为内联的方式;
 
  6、使用级联比较 “x < y < z” 而不是 “x < y and y < z”;
 
  7、while 1 要比 while True 更快(当然后者的可读性更好);
 
  8、build in 函数通常较快,add(a,b) 要优于 a+b。
 
 定位程序性能瓶颈
 
  对代码优化的前提是需要了解性能瓶颈在什么地方,程序运行的主要时间是消耗在哪里,对于比较复杂的代码可以借助一些工具来定位,python 内置了丰富的性能分析工具,如 profile,cProfile 与 hotshot 等。其中 Profiler 是 python 自带的一组程序,能够描述程序运行时候的性能,并提供各种统计帮助用户定位程序的性能瓶颈。Python 标准模块提供三种 profilers:cProfile,profile 以及 hotshot。
 
  profile 的使用非常简单,只需要在使用之前进行 import 即可。具体实例如下:
 
  清单 8. 使用 profile 进行性能分析

复制代码 代码如下:

import profile
 def profileTest():
    Total =1;
    for i in range(10):
        Total=Total*(i+1)
        print Total
    return Total
 if __name__ == "__main__":
    profile.run("profileTest()")

  程序的运行结果如下:
 
  图 1. 性能分析结果

  其中输出每列的具体解释如下:
 •ncalls:表示函数调用的次数;
 •tottime:表示指定函数的总的运行时间,除掉函数中调用子函数的运行时间;
 •percall:(第一个 percall)等于 tottime/ncalls;
 •cumtime:表示该函数及其所有子函数的调用运行的时间,即函数开始调用到返回的时间;
 •percall:(第二个 percall)即函数运行一次的平均时间,等于 cumtime/ncalls;
 •filename:lineno(function):每个函数调用的具体信息;
 
  如果需要将输出以日志的形式保存,只需要在调用的时候加入另外一个参数。如 profile.run(“profileTest()”,”testprof”)。
 
  对于 profile 的剖析数据,如果以二进制文件的时候保存结果的时候,可以通过 pstats 模块进行文本报表分析,它支持多种形式的报表输出,是文本界面下一个较为实用的工具。使用非常简单:

复制代码 代码如下:

import pstats
 p = pstats.Stats('testprof')
 p.sort_stats("name").print_stats()

  其中 sort_stats() 方法能够对剖分数据进行排序, 可以接受多个排序字段,如 sort_stats(‘name', ‘file') 将首先按照函数名称进行排序,然后再按照文件名进行排序。常见的排序字段有 calls( 被调用的次数 ),time(函数内部运行时间),cumulative(运行的总时间)等。此外 pstats 也提供了命令行交互工具,执行 python – m pstats 后可以通过 help 了解更多使用方式。
 
  对于大型应用程序,如果能够将性能分析的结果以图形的方式呈现,将会非常实用和直观,常见的可视化工具有 Gprof2Dot,visualpytune,KCacheGrind 等,读者可以自行查阅相关官网,本文不做详细讨论。
 
 Python 性能优化工具
 
  Python 性能优化除了改进算法,选用合适的数据结构之外,还有几种关键的技术,比如将关键 python 代码部分重写成 C 扩展模块,或者选用在性能上更为优化的解释器等,这些在本文中统称为优化工具。python 有很多自带的优化工具,如 Psyco,Pypy,Cython,Pyrex 等,这些优化工具各有千秋,本节选择几种进行介绍。
 
  Psyco
 
  psyco 是一个 just-in-time 的编译器,它能够在不改变源代码的情况下提高一定的性能,Psyco 将操作编译成有点优化的机器码,其操作分成三个不同的级别,有”运行时”、”编译时”和”虚拟时”变量。并根据需要提高和降低变量的级别。运行时变量只是常规 Python 解释器处理的原始字节码和对象结构。一旦 Psyco 将操作编译成机器码,那么编译时变量就会在机器寄存器和可直接访问的内存位置中表示。同时 python 能高速缓存已编译的机器码以备今后重用,这样能节省一点时间。但 Psyco 也有其缺点,其本身运行所占内存较大。目前 psyco 已经不在 python2.7 中支持,而且不再提供维护和更新了,对其感兴趣的可以参考 http://psyco.sourceforge.net/
 
  Pypy
 
  PyPy 表示 “用 Python 实现的 Python”,但实际上它是使用一个称为 RPython 的 Python 子集实现的,能够将 Python 代码转成 C, .NET, Java 等语言和平台的代码。PyPy 集成了一种即时 (JIT) 编译器。和许多编译器,解释器不同,它不关心 Python 代码的词法分析和语法树。 因为它是用 Python 语言写的,所以它直接利用 Python 语言的 Code Object.。 Code Object 是 Python 字节码的表示,也就是说, PyPy 直接分析 Python 代码所对应的字节码 ,,这些字节码即不是以字符形式也不是以某种二进制格式保存在文件中, 而在 Python 运行环境中。目前版本是 1.8. 支持不同的平台安装,windows 上安装 Pypy 需要先下载 https://bitbucket.org/pypy/pypy/downloads/pypy-1.8-win32.zip,然后解压到相关的目录,并将解压后的路径添加到环境变量 path 中即可。在命令行运行 pypy,如果出现如下错误:”没有找到 MSVCR100.dll, 因此这个应用程序未能启动,重新安装应用程序可能会修复此问题”,则还需要在微软的官网上下载 VS 2010 runtime libraries 解决该问题。具体地址为http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=5555
 
  安装成功后在命令行里运行 pypy,输出结果如下:

精彩图集

赞助商链接