如何提高python性能

在Python解析器中输入 import
this. 一个犀利的Python新手可能会注意到"解析"一词, 认为Python不过是另一门脚本语言. "它肯定很慢!"

毫无疑问:Python程序没有编译型语言高效快速. 甚至Python拥护者们会告诉你Python不适合这些领域. 然而,YouTube已用Python服务于每小时4千万视频的请求.
你所要做的就是编写高效的代码和需要时使用外部实现(C/C++)代码. 这里有一些建议,可以帮助你成为一个更好的Python开发者:

1. 使用内建函数:

你可以用Python写出高效的代码,但很难击败内建函数.
经查证. 他们非常快速.

2.使用join()连接字符串.

你可以使用 "+" 来连接字符串. 但由于string在Python中是不可变的,每一个"+"操作都会创建一个新的字符串并复制旧内容. 常见用法是使用Python的数组模块单个的修改字符;当完成的时候,使用 join() 函数创建最终字符串.

>>> #This is good to glue a large number of strings

>>> for chunk in input():

>>>    my_string.join(chunk)

3.
使用Python多重赋值,交换变量

这在Python中即优雅又快速:

>>> x, y = y, x

这样很慢:

>>> temp = x

>>> x = y

>>> y = temp

4.
尽量使用局部变量

Python 检索局部变量比检索全局变量快. 这意味着,避免 "global" 关键字.

5.
尽量使用 "in"

使用 "in" 关键字. 简洁而快速.

>>> for key in sequence:

>>>     print “found”

6.
使用延迟加载加速

將 "import" 声明移入函数中,仅在需要的时候导入. 换句话说,如果某些模块不需马上使用,稍后导入他们. 例如,你不必在一开使就导入大量模块而加速程序启动. 该技术不能提高整体性能.
但它可以帮助你更均衡的分配模块的加载时间.

7.
为无限循环使用 "while 1"

有时候在程序中你需一个无限循环.(例如一个监听套接字的实例)
尽管 "while true" 能完成同样的事, 但 "while 1" 是单步运算. 这招能提高你的Python性能.

>>> while 1:

>>>    #do stuff, faster with while 1

>>> while True:

>>>    # do stuff, slower with wile True

8. 使用list
comprehension

从Python 2.0 开始,你可以使用 list comprehension 取代大量的 "for" 和 "while" 块. 使用List comprehension通常更快,Python解析器能在循环中发现它是一个可预测的模式而被优化.额外好处是,list
comprehension更具可读性(函数式编程),并在大多数情况下,它可以节省一个额外的计数变量。例如,让我们计算1到10之间的偶数个数:

>>> # the good way to iterate a range

>>> evens = [ i for i in range(10) if i%2 == 0]

>>> [0, 2, 4, 6, 8]

>>> # the following is not so Pythonic

>>> i = 0

>>> evens = []

>>> while i < 10:

>>>    if i %2 == 0: evens.append(i)

>>>    i += 1

>>> [0, 2, 4, 6, 8]

9.
使用xrange()处理长序列:

这样可为你节省大量的系统内存,因为xrange()在序列中每次调用只产生一个整数元素。而相反 range(),它將直接给你一个完整的元素列表,用于循环时会有不必要的开销。

10. 使用 Python generator:

这也可以节省内存和提高性能。例如一个视频流,你可以一个一个字节块的发送,而不是整个流。例如,

>>> chunk = ( 1000 * i for i in xrange(1000))

>>> chunk

<generator object <genexpr> at 0x7f65d90dcaa0>

>>> chunk.next()

0

>>> chunk.next()

1000

>>> chunk.next()

2000

11. 了解itertools模块:

该模块对迭代和组合是非常有效的。让我们生成一个列表[1,2,3]的所有排列组合,仅需三行Python代码:

>>> import itertools

>>> iter = itertools.permutations([1,2,3])

>>> list(iter)

[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

12. 学习bisect模块保持列表排序:

这是一个免费的二分查找实现和快速插入有序序列的工具。也就是说,你可以使用:

>>> import bisect

>>> bisect.insort(list, element)

你已將一个元素插入列表中, 而你不需要再次调用 sort() 来保持容器的排序, 因为这在长序列中这会非常昂贵.

13. 理解Python列表,实际上是一个数组:

Python中的列表实现并不是以人们通常谈论的计算机科学中的普通单链表实现的。Python中的列表是一个数组。也就是说,你可以以常量时间O(1) 检索列表的某个元素,而不需要从头开始搜索。这有什么意义呢?
Python开发人员使用列表对象insert()时, 需三思. 例如:>>> list.insert(0,item)

在列表的前面插入一个元素效率不高, 因为列表中的所有后续下标不得不改变. 然而,您可以使用list.append()在列表的尾端有效添加元素. 挑先deque,如果你想快速的在两插入或时。它是快速的,因为在Python中的deque用双链表实现。不再多说。

14.
使用dict 和 set 测试成员:

检查一个元素是在dicitonary或set是否存在
这在Python中非常快的。这是因为dict和set使用哈希表来实现。查找效率可以达到O(1)。因此,如果您需要经常检查成员,使用 set 或 dict做为你的容器.

>>> mylist = [‘a‘, ‘b‘, ‘c‘] #Slower, check membership with list:

>>> ‘c’ in mylist

>>> True

>>> myset = set([‘a‘, ‘b‘, ‘c‘]) # Faster, check membership with set:

>>> ‘c’ in myset:

>>> True

15. 使用Schwartzian Transform 的 sort():

原生的list.sort()函数是非常快的。 Python会按自然顺序排序列表。有时,你需要非自然顺序的排序。例如,你要根据服务器位置排序的IP地址。 Python支持自定义的比较,你可以使用list.sort(CMP()),这会比list.sort()慢,因为增加了函数调用的开销。如果性能有问 题,你可以申请Guttman-Rosler Transform,基于Schwartzian Transform. 它只对实际的要用的算法有兴趣,它的简要工作原理是,你可以变换列表,并调用Python内置list.sort()
- > 更快,而无需使用list.sort(CMP() )->慢。

16.
Python装饰器缓存结果: 14. 使用dict 和 set 测试成员:

“@”符号是Python的装饰语法。它不只用于追查,锁或日志。你可以装饰一个Python函数,记住调用结果供后续使用。这种技术被称为memoization的。下面是一个例子:

>>> from functools import wraps

>>> def memo(f):

>>>    cache = { }

>>>    @wraps(f)

>>>    def  wrap(*arg):

>>>        if arg not in cache: cache[‘arg‘] = f(*arg)

>>>        return cache[‘arg‘]

>>>    return wrap

们也可以对
Fibonacci 函数使用装饰器: 

>>> @memo

>>> def fib(i):

>>>    if i < 2: return 1

>>>    return fib(i-1) + fib(i-2)

这里的关键思想是:增强函数(装饰)函数,记住每个已经计算的Fibonacci值;如果它们在缓存中,就不需要再计算了.

17. 理解Python的GIL(全局解释器锁):

GIL是必要的,因为CPython的内存管理是非线程安全的。你不能简单地创建多个线程,并希望Python能在多核心的机器上运行得更快。这是因为 GIL將会防止多个原生线程同时执行Python字节码。换句话说,GIL將序列化您的所有线程。然而,您可以使用线程管理多个派生进程加速程序,这些程
序独立的运行于你的Python代码外。

18. 像熟悉文档一样的熟悉Python源代码:

Python有些模块为了性能使用C实现。当性能至关重要而官方文档不足时,可以自由探索源代码。你可以找到底层的数据结构和算法。 Python的源码库就是一个很棒的地方:http://svn.python.org/view/python/trunk/Modules

结论:

这些不能替代大脑思考. 打开引擎盖充分了解是开发者的职责,使得他们不会快速拼凑出一个垃圾设计. 本文的Python建议可以帮助你获得好的性能. 如果速度还不够快, Python將需要借助外力:分析和运行外部代码.我们將在本文的第二部分中涉及.

第二部分

有益的提醒,静态编译的代码仍然重要. 仅例举几例, Chrome,Firefox,MySQL,MS Office 和 Photoshop都是高度优化的软件,我们每天都在使用. Python作为解析语言,很明显不适合. 不能单靠Python来满足那些性能是首要指示的领域.  这就是为什么Python支持让你接触底层裸机基础设施的原因, 将更繁重的工作代理给更快的语言如C. 这高性能计算和嵌入式编程中是关键的功能. Python性能鸡汤第一部分讨论了怎样高效的使用Python. 在第二部分, 我们將涉及监控和扩展Python.

1. 首先, 拒绝调优诱惑

调优给你的代码增加复杂性. 集成其它语言之前, 请检查下面的列表. 如果你的算法是"足够好", 优化就没那么迫切了.

1. 你做了性能测试报告吗?

2. 你能减少硬盘的 I/O 访问吗?

3. 你能减少网络 I/O 访问吗?

4. 你能升级硬件吗?

5. 你是为其它开发者编译库吗?

6.你的第三方库软件是最新版吗?

2. 使用工具监控代码,
而不是直觉

速度的问题可能很微妙, 所以不要依赖于直觉. 感谢 "cprofiles" 模块, 通过简单的运行你就可以监控Python代码

“python -m cProfile myprogram.py”

我们写了个测试程序. 基于黑盒监控. 这里的瓶颈是 "very_slow()" 函数调用. 我们还可以看到 "fast()" 和 "slow()"都被调用200次. 这意味着, 如果我们可以改善 "fast()" 和 "slow()" 函数, 我们可以获得全面的性能提升. cprofiles 模块也可以在运行时导入. 这对于检查长时间运行的进程非常有用.

3. 审查时间复杂度

控制以后, 提供一个基本的算法性能分析. 恒定时间是理想值. 对数时间复度是稳定的. 阶乘复杂度很难扩展.

O(1) -> O(lg n) -> O(n lg n) -> O(n^2) -> O(n^3) -> O(n^k) -> O(k^n) -> O(n!)

4. 使用第三方包

有很多为Python设计的高性能的第三方库和工具. 下面是一些有用的加速包的简短列表.

1. NumPy:
一个开源的相当于MatLab的包

2. SciPy:
另一个数值处理库

3. GPULib:
使用GPUs加速代码

4. PyPy:
使用 just-in-time 编译器优化Python代码

5. Cython:
將Python优码转成C

6. ShedSkin: 將Python代码转成C++

5. 使用multiprocessing模块实现真正的并发

因为GIL会序列化线程, Python中的多线程不能在多核机器和集群中加速. 因此Python提供了multiprocessing模块, 可以派生额外的进程代替线程, 跳出GIL的限制.
此外, 你也可以在外部C代码中结合该建议, 使得程序更快.

注意, 进程的开销通常比线程昂贵, 因为线程自动共享内存地址空间和文件描述符. 意味着, 创建进程比创建线程会花费更多, 也可能花费更多内存. 这点在你计算使用多处理器时要牢记.

6. 本地代码

好了, 现在你决定为了性能使用本地代码. 在标准的ctypes模块中, 你可以直接加载已编程的二进制库(.dll 或 .so文件)到Python中, 无需担心编写C/C++代码或构建依赖.
例如, 我们可以写个程序加载libc来生成随机数.

然而, 绑定ctypes的开销是非轻量级的. 你可以认为ctypes是一个粘合操作系库函数或者硬件设备驱动的胶水. 有几个如 SWIG, Cython和Boost 此类Python直接植入的库的调用比ctypes开销要低. Python支持面向对象特性, 如类和继承. 正如我们看到的例子, 我们可以保留常规的C++代码, 稍后导入. 这里的主要工作是编写一个包装器 (行 10~18).

总结:

我希望这些Python建议能让你成为一个更好的开发者. 最后, 我需要指出, 追求性能极限是一个有趣的游戏, 而过度优化就会变成嘲弄了. 虽然Python授予你与C接口无缝集成的能力, 你必须问自己你花数小时的艰辛优化工作用户是否买帐. 另一方面, 牺牲代码的可维护性换取几毫秒的提升是否值得. 团队中的成员常常会感谢你编写了简洁的代码. 尽量贴近Python的方式, 因为人生苦短.

英文原文:http://blog.monitis.com/index.php/2012/02/13/python-performance-tips-part-1/

英文原文:http://blog.monitis.com/index.php/2012/03/21/python-performance-tips-part-2/

时间: 2024-10-11 22:08:20

如何提高python性能的相关文章

提高Python性能的一些建议(一)

最近换住的地方,网费到期,有两个星期没更新博客了,博客还是要坚持写的,有时候工作时遇到了相关问题,查看相关博客,还是能够得到一些思路或者灵感.虽然写篇博客要话费不少时间(我一般要花一个半小时到两个小时之间),但是这中间码字呀.归纳总结的过程还是让我受益匪浅的,温故而知新!当然分享自己的学习心得,也会让自己认识一些志同道合的朋友,也挺好.不说许多,今天讲讲如何提高Python性能的问题. python的性能相对c语言等还是有一定的劣势,但是如果能掌握一些优化性能的技巧,不仅能够提高代码的运行效率,

Python性能鸡汤(转)

英文原文:http://blog.monitis.com/index.php/2012/02/13/python-performance-tips-part-1/ 英文原文:http://blog.monitis.com/index.php/2012/03/21/python-performance-tips-part-2/ 译文:http://www.oschina.net/question/1579_45822 Python是解释型语言,因此它的执行效率不高 [1] ,但这并不影响它的流行.

使用 libevent 和 libev 提高网络应用性能

使用 libevent 和 libev 提高网络应用性能 Martin C. Brown, 作家, Freelance 简介: 构建现代的服务器应用程序需要以某种方法同时接收数百.数千甚至数万个事件,无论它们是内部请求还是网络连接,都要有效地处理它们的操作.有许多解决方案,但是 libevent 库和 libev 库能够大大提高性能和事件处理能力.在本文中,我们要讨论在 UNIX® 应用程序中使用和部署这些解决方案所用的基本结构和方法.libev 和 libevent 都可以在高性能应用程序中使

Python性能(转)

第一部分 阅读 Zen of Python,在Python解析器中输入 import this. 一个犀利的Python新手可能会注意到"解析"一词, 认为Python不过是另一门脚本语言. "它肯定很慢!" 毫无疑问:Python程序没有编译型语言高效快速. 甚至Python拥护者们会告诉你Python不适合这些领域. 然而,YouTube已用Python服务于每小时4千万视频的请求. 你所要做的就是编写高效的代码和需要时使用外部实现(C/C++)代码. 这里有一

Python性能鸡汤

第一部分 阅读 Zen of Python,在Python解析器中输入 import this. 一个犀利的Python新手可能会注意到"解析"一词, 认为Python不过是另一门脚本语言. "它肯定很慢!" 毫无疑问:Python程序没有编译型语言高效快速. 甚至Python拥护者们会告诉你Python不适合这些领域. 然而,YouTube已用Python服务于每小时4千万视频的请求. 你所要做的就是编写高效的代码和需要时使用外部实现(C/C++)代码. 这里有一

Python性能优化(转)

分成两部分:代码优化和工具优化 原文:http://my.oschina.net/xianggao/blog/102600 阅读 Zen of Python,在Python解析器中输入 import this. 一个犀利的Python新手可能会注意到"解析"一词, 认为Python不过是另一门脚本语言. "它肯定很慢!" 毫无疑问:Python程序没有编译型语言高效快速. 甚至Python拥护者们会告诉你Python不适合这些领域. 然而,YouTube已用Pyth

[译]用NGINX最大化发挥PYTHON性能

原文:Maximizing Python Performance with NGINX, Part I: Web Serving and Caching 介绍NGINX和Python如何配合使用 Python以易用,有趣而出名,它让软件开发变得简单,据说运行性能也高于其他脚本语言(PHP最新版本PHP 7的性能好像可以与Python一较高下) 每一个人都希望自己的网站或应用可以运行得更快.但是每一个网站在大流量和流量激增时都容易遇到性能问题,甚至当机,业务繁忙时,这种情况会更加糟糕.其实无论流量

6个Python性能优化技巧

ython是一门非常酷的语言,因为很少的Python代码可以在短时间内做很多事情,并且,Python很容易就能支持多任务和多重处理. Python的批评者声称Python性能低效.执行缓慢,但实际上并非如此:尝试以下6个小技巧,可以加快Python应用程序. 1.关键代码可以依赖于扩展包 Python使许多编程任务变得简单,但是对于很关键的任务并不总是提供最好的性能.使用C.C++或者机器语言扩展包来执行关键任务能极大改善性能.这些包是依赖于平台的,也就是说,你必须使用特定的.与你使用的平台相关

python性能测量工具cProfile

背景: Python是一种解释性的语言,执行速度相比C.C++等语言十分缓慢:因此我们需要在其它地方上下功夫来提高代码的执行速度.首先需要对代码进行分析,这个时候则需要用一些工具.这里介绍cProfile:全代码分析:命令行: cProfile -s tottime your_program.py结果如下: 1 2 3 4 5 6 7 8 9 10 ncalls tottime percall cumtime percall filename:lineno(function) 66 0.001