提升Python程序运行效率的6个方法


Posted in Python onMarch 31, 2015

Python是一个很酷的语言,因为你可以在很短的时间内利用很少的代码做很多事情。不仅如此,它还能轻松地支持多任务,比如多进程等。Python批评者有时会说Python执行缓慢。本文将尝试介绍6个技巧,可加速你的Python应用程序。
1.让关键代码依赖于外部包

虽然Python让许多编程任务变得容易,但它可能并不总能为紧急的任务提供最佳性能。你可以为紧急的任务使用C、C++或机器语言编写的外部包,这样可以提高应用程序的性能。这些包都是不能跨平台的,这意味着你需要根据你正在使用的平台,寻找合适的包。简而言之,这个方案放弃了一些应用程序的可移植性,以换取只有在特定主机上直接编程才能获得的程序性能。这里有一些你应该考虑加入到你的“性能兵工厂”的包:

  •     Cython
  •    PyInlne
  •     PyPy
  •     Pyrex

这些包以不同的方式提高性能。例如,Pyrex能够扩展Python所能做的事情,例如使用C的数据类型来让内存任务更加有效或直接。PyInIne让你在Python应用程序中直接使用C代码。程序中的内联代码单独编译,但它在利用C语言所能提供的效率的同时,也让所有的代码都在同一个地方。
2.排序时使用键(key)

有很多老的Python排序代码,它们在你创建一个自定义的排序时花费你的时间,但在运行时确实能加速执行排序过程。元素排序的最好方法是尽可能使用键(key)和默认的sort()排序方法。例如,考虑下面的代码:

import operator
somelist = [(1, 5, 8), (6, 2, 4), (9, 7, 5)]
somelist.sort(key=operator.itemgetter(0))
somelist
#Output = [(1, 5, 8), (6, 2, 4), (9, 7, 5)]
somelist.sort(key=operator.itemgetter(1))
somelist
#Output = [(6, 2, 4), (1, 5, 8), (9, 7, 5)]
somelist.sort(key=operator.itemgetter(2))
somelist
#Output = [(6, 2, 4), (9, 7, 5), (1, 5, 8)],

每一个实例中,根据你选择的作为key参数部分的索引,数组进行了排序。类似于利用数字进行排序,这种方法同样适用于利用字符串排序。
3.优化循环

每种编程语言都会强调需要优化循环。当使用Python的时候,你可以依靠大量的技巧使得循环运行得更快。然而,开发者经常漏掉的一个方法是:避免在一个循环中使用点操作。例如,考虑下面的代码:

lowerlist = ['this', 'is', 'lowercase']
upper = str.upper
upperlist = []
append = upperlist.append
for word in lowerlist:
  append(upper(word))
  print(upperlist)
  #Output = ['THIS', 'IS', 'LOWERCASE']

每一次你调用方法str.upper,Python都会求该方法的值。然而,如果你用一个变量代替求得的值,值就变成了已知的,Python就可以更快地执行任务。优化循环的关键,是要减少Python在循环内部执行的工作量,因为Python原生的解释器在那种情况下,真的会减缓执行的速度。

(注意:优化循环的方法有很多,这只是其中的一个。例如,许多程序员都会说,列表推导是在循环中提高执行速度的最好方式。这里的关键是,优化循环是程序取得更高的执行速度的更好方式之一。)
4.使用较新版本的Python

在网上搜索Python信息,都会发现无数人在问,从Python一个版本迁移到另一个版本的问题的信息。一般来说,Python的每一个版本都包含了能让其比上个版本运行更快的优化。版本迁移的限制因素是,你喜欢的那些库是否已经迁移到Python的较新版本。相比于询问是否应该进行版本迁移,关键问题是确定一个新版本什么时候有足够的支持,以保证迁移的可行性。

你需要验证你的代码仍然运行。你需要在Python的新版本下使用你获得的新库,然后检查你的应用程序是否需要重大改变。只有在你作出必要的更正之后,你才会注意到版本之间的差别。然而,如果你正好确保你的应用程序能在新版本下运行,而不需要任何改变,你可能会错过那些版本升级带来的新特性。一旦你进行了迁移,你应该为你的新版本下的应用程序写一个说明,检查有问题的地方,并且优先考虑利用新版本的特性去更新那些地方。这样用户将会在升级的过程中更早的看到一个更大的性能提升。
5.尝试多种编码方法

如果每次你创建一个应用程序都是用相同的编码方法,几乎肯定会导致一些你的应用程序比它能够达到的运行效率慢的情况。作为分析过程的一部分,你可以尝试一些实验。例如,在一个字典中管理一些元素,你可以采用安全的方法确定元素是否已经存在并更新,或者你可以直接添加元素,然后作为异常处理该元素不存在情况。考虑第一个编码的例子:

n = 16
myDict = {}
for i in range(0, n):
  char = 'abcd'[i%4]
  if char not in myDict:
    myDict[char] = 0
    myDict[char] += 1
    print(myDict)

这段代码通常会在myDict开始为空时运行得更快。然而,当mydict通常被数据填充(或者至少大部分被充填)时,另一种方法效果更好。

n = 16
myDict = {}
for i in range(0, n):
  char = 'abcd'[i%4]
  try:
    myDict[char] += 1
  except KeyError:
    myDict[char] = 1
  print(myDict)

两种情况下具有相同的输出:{‘d': 4, ‘c': 4, ‘b': 4, ‘a': 4}。唯一的不同是这个输出是如何得到的。跳出固定的思维模式,创造新的编码技巧,能够帮助你利用你的应用程序获得更快的结果。
6.交叉编译应用程序

开发者有时会忘记,电脑实际上是不懂任何用于创建现代应用程序的语言,电脑所能懂得是机器代码。为了能在电脑上运行应用程序,你使用一个应用将人类可读的代码你转换成计算机能理解的。有时候用一种语言,比如Python,写一个应用,并用另一种语言,比如C++,运行它,从性能的角度来看是有意义的。这取决于你想要应用程序去做什么,以及主机系统可以提供的资源。

一个有趣的交叉编译器,Nuitka,可以将你的Python代码转换为C++代码。这么做的结果是,你可以在原生模式下执行应用程序,而不是依靠解释器。根据平台和任务,你可以看到一个显著的性能提升。

(注意:Nuitka目前还处于测试阶段,所以用它来产品程序时需要小心。实际上,目前最好将其用于实验。现在也有一些关于交叉编译是否是得到更好性能的最佳方式的讨论。开发者已经利用交叉编译好几年了,目的是实现特定的目标,比如更好的应用程序的速度。记住,每一个解决方案都会有得有失,你应该在将一个解决方案用于生产环境之前就好好考虑一下得失情况。)

在使用一个交叉编译器时,要确保它支持你使用的Python的版本。Nuitka支持Python2.6、2.7、3.2和3.3。想让这个方案发挥作用,你需要一个Python解释器和一个C++编译器。Nuitka支持多种C++编译器,包括Microsoft Visual Studio、MinGW 和 Clang/LLVM。

交叉编译也可能带来一些严重的负面影响。例如,当利用Nuitka工作时,你会发现即使一个小程序也能消耗很大的硬盘空间,这是因为Nuitka使用大量的动态链接库(DLLs)实现Python的功能。所以当你面对一个资源有限的系统时,这个方案可能不会很好的起作用。
总结

这六个技巧中的任意一个,都可以帮助你创造更快的Python程序。但任何技巧都不是万能的,不能每次都起作用。有些技巧在Python的特定版本下比其他技巧的更有效——甚至系统平台也能影响它们的效果。你需要配置你的应用,确定哪个地方让其运行缓慢,然后尝试似乎能最好的解决这些问题的一些技巧。

Python 相关文章推荐
python实现代理服务功能实例
Nov 15 Python
约瑟夫问题的Python和C++求解方法
Aug 20 Python
Python中常见的数据类型小结
Aug 29 Python
Caffe均值文件mean.binaryproto转mean.npy的方法
Jul 09 Python
python常用函数与用法示例
Jul 02 Python
更新pip3与pyttsx3文字语音转换的实现方法
Aug 08 Python
最新2019Pycharm安装教程 亲测
Feb 28 Python
Python爬虫工具requests-html使用解析
Apr 29 Python
Python轻量级web框架bottle使用方法解析
Jun 13 Python
Python SMTP发送电子邮件的示例
Sep 23 Python
python代码实现图书管理系统
Nov 30 Python
Python tensorflow卷积神经Inception V3网络结构
May 06 Python
用Python从零实现贝叶斯分类器的机器学习的教程
Mar 31 #Python
利用Python的Flask框架来构建一个简单的数字商品支付解决方案
Mar 31 #Python
用Python进行基础的函数式编程的教程
Mar 31 #Python
python使用多线程不断刷新网页的方法
Mar 31 #Python
Python新手实现2048小游戏
Mar 31 #Python
举例介绍Python中的25个隐藏特性
Mar 30 #Python
在Python的循环体中使用else语句的方法
Mar 30 #Python
You might like
thinkPHP通用控制器实现方法示例
2017/11/23 PHP
PHP实现一维数组与二维数组去重功能示例
2018/05/24 PHP
PHP PDOStatement::rowCount讲解
2019/02/01 PHP
IE6不能修改NAME问题的解决方法
2010/09/03 Javascript
关于jQuery中.attr()和.prop()的问题探讨
2013/09/06 Javascript
JavaScript判断变量是否为undefined的两种写法区别
2013/12/04 Javascript
Express作者TJ告别Node.js奔向Go
2014/07/14 Javascript
简单实现异步编程promise模式
2015/07/31 Javascript
原生js实现图片轮播特效
2015/12/18 Javascript
JS定时器用法分析【时钟与菜单中的应用】
2016/12/21 Javascript
JavaScript DOM节点操作实例小结(新建,删除HTML元素)
2017/01/19 Javascript
vue学习笔记之vue1.0和vue2.0的区别介绍
2017/05/17 Javascript
[js高手之路]设计模式系列课程-发布者,订阅者重构购物车的实例
2017/08/29 Javascript
浅谈react.js中实现tab吸顶效果的问题
2017/09/06 Javascript
为什么使用koa2搭建微信第三方公众平台的原因
2018/05/16 Javascript
vue打包的时候自动将px转成rem的操作方法
2018/06/20 Javascript
jquery 动态遍历select 赋值的实例
2018/09/12 jQuery
react-navigation之动态修改title的内容
2018/09/26 Javascript
node上的redis调用优化示例详解
2018/10/30 Javascript
vue router总结 $router和$route及router与 router与route区别
2019/07/05 Javascript
Js代码中的span拼接问题解决
2019/11/22 Javascript
Vue中实现回车键切换焦点的方法
2020/02/19 Javascript
基于python爬虫数据处理(详解)
2017/06/10 Python
python矩阵转换为一维数组的实例
2018/06/05 Python
谈谈Python:为什么类中的私有属性可以在外部赋值并访问
2020/03/05 Python
python判断正负数方式
2020/06/03 Python
英国信箱在线鲜花速递公司:Bloom & Wild
2019/03/10 全球购物
请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1
2015/07/16 面试题
Java如何读取CLOB字段
2013/10/10 面试题
初中教师个人总结
2015/02/10 职场文书
2015年秘书个人工作总结
2015/04/25 职场文书
仓库管理制度范本
2015/08/04 职场文书
周末问候语大全
2015/11/10 职场文书
2016中学教师读书心得体会
2016/01/13 职场文书
Django项目配置Memcached和Redis, 缓存选择哪个更有优势
2021/04/06 Python
MIME类型中application/xml与text/xml的区别介绍
2022/01/18 HTML / CSS