提升Python运行效率的六个窍门

曾灵敏 — MAY 18, 2015
Python是一门优秀的语言,它能让你在短期内经过极少许代码就能完成许多操做。不只如此,它还轻松支持多任务处理,好比多进程。python

不喜欢Python的人常常会吐嘈Python运行太慢。可是,事实并不是如此。尝试如下六个窍门,来为你的Python应用提速。程序员

窍门一:关键代码使用外部功能包

Python简化了许多编程任务,可是对于一些时间敏感的任务,它的表现常常不尽人意。使用C/C++或机器语言的外部功能包处理时间敏感任务,能够有效提升应用的运行效率。这些功能包每每依附于特定的平台,所以你要根据本身所用的平台选择合适的功能包。简而言之,这个窍门要你牺牲应用的可移植性以换取只有经过对底层主机的直接编程才能得到的运行效率。如下是一些你能够选择用来提高效率的功能包:web

Cython
Pylnlne
PyPy
Pyrex编程

 
这些功能包的用处各有不一样。好比说,使用C语言的数据类型,可使涉及内存操做的任务更高效或者更直观。Pyrex就能帮助Python延展出这样的功能。Pylnline能使你在Python应用中直接使用C代码。内联代码是独立编译的,可是它把全部编译文件都保存在某处,并能充分利用C语言提供的高效率。小程序

窍门二:在排序时使用键

Python含有许多古老的排序规则,这些规则在你建立定制的排序方法时会占用不少时间,而这些排序方法运行时也会拖延程序实际的运行速度。最佳的排序方法实际上是尽量多地使用键和内置的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)],

在每段例子里,list都是根据你选择的用做关键参数的索引进行排序的。这个方法不只对数值类型有效,还一样适用于字符串类型。app

窍门三:针对循环的优化

每一种编程语言都强调最优化的循环方案。当使用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解释执行的特性,在上面的例子中会大大减慢它的速度。svg

(注意:优化循环的方法还有不少,这只是其中之一。好比,不少程序员会认为,列表推导式是提升循环速度的最佳方法。关键在于,优化循环方案是提升应用程序运行速度的上佳选择。)函数

窍门四:使用较新的Python版本

若是你在网上搜索Python,你会发现数不尽的信息都是关于如何升级Python版本。一般,每一个版本的Python都会包含优化内容,使其运行速度优于以前的版本。可是,限制因素在于,你最喜欢的函数库有没有同步更新支持新的Python版本。与其争论函数库是否应该更新,关键在于新的Python版本是否足够高效来支持这一更新。

你要保证本身的代码在新版本里还能运行。你须要使用新的函数库才能体验新的Python版本,而后你须要在作出关键性的改动时检查本身的应用。只有当你完成必要的修正以后,你才能体会新版本的不一样。

然而,若是你只是确保本身的应用在新版本中能够运行,你极可能会错过新版本提供的新特性。一旦你决定更新,请分析你的应用在新版本下的表现,并检查可能出问题的部分,而后优先针对这些部分应用新版本的特性。只有这样,用户才能在更新之初就觉察到应用性能的改观。

窍门五:尝试多种编码方法

每次建立应用时都使用同一种编码方法几乎无一例外会致使应用的运行效率不尽人意。能够在程序分析时尝试一些试验性的办法。譬如说,在处理字典中的数据项时,你既可使用安全的方法,先确保数据项已经存在再进行更新,也能够直接对数据项进行更新,把不存在的数据项做为特例分开处理。请看下面第一段代码:

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)

在两种方法中输出结果都是同样的。区别在于输出是如何得到的。跳出常规的思惟模式,建立新的编程技巧能使你的应用更有效率。

窍门六:交叉编译你的应用

开发者有时会忘记计算机其实并不理解用来建立现代应用程序的编程语言。计算机理解的是机器语言。为了运行你的应用,你借助一个应用将你所编的人类可读的代码转换成机器可读的代码。有时,你用一种诸如Python这样的语言编写应用,再以C++这样的语言运行你的应用,这在运行的角度来讲,是可行的。关键在于,你想你的应用完成什么事情,而你的主机系统能提供什么样的资源。

Nuitka是一款有趣的交叉编译器,能将你的Python代码转化成C++代码。这样,你就能够在native模式下执行本身的应用,而无需依赖于解释器程序。你会发现本身的应用运行效率有了较大的提升,可是这会因平台和任务的差别而有所不一样。

(注意:Nuitka如今还处在测试阶段,因此在实际应用中请多加注意。实际上,当下最好仍是把它用于实验。此外,关于交叉编译是否为提升运行效率的最佳方法还存在讨论的空间。开发者已经使用交叉编译多年,用来提升应用的速度。记住,每一种解决办法都有利有弊,在把它用于生产环境以前请仔细权衡。)

在使用交叉编译器时,记得确保它支持你所用的Python版本。Nuitka支持Python2.6, 2.7, 3.2和3.3。为了让解决方案生效,你须要一个Python解释器和一个C++编译器。Nuitka支持许多C++编译器,其中包括Microsoft Visual Studio,MinGWClang/LLVM

交叉编译可能形成一些严重问题。好比,在使用Nuitka时,你会发现即使是一个小程序也会消耗巨大的驱动空间。由于Nuitka借助一系列的动态连接库(DDLs)来执行Python的功能。所以,若是你用的是一个资源颇有限的系统,这种方法或许不太可行。

结论

前文所述的六个窍门都能帮助你建立运行更有效率的Python应用。可是银弹是不存在的。上述的这些窍门不必定每次都能奏效。在特定的Python的版本下,有的窍门或许比其余的表现更好,但这有时候甚至取决于平台的差别。你须要总结分析你的应用,找到它效率低下的部分,而后尝试这些窍门,找到解决问题的最佳方法。


本文做者系OneAPM工程师李哲 ,想阅读更多好的技术文章,请访问OneAPM官方技术博客。