#pragma section-numbers off = 8-18soundex.xml 性能优化 = <> <> == 18.1 概览 == 1. `Para 5`:哦,是的,单元测试。不必我说,在开始性能优化之前你需要一个完全的单元测试集。'''你需要的最后一件事情就是在乱动你的算法时引入新的问题。'''<
> (./) '''你最不需要的'''就是在乱动你的算法时引入新的问题。 1. `Para 6`:''With these caveats in place, let's look at some techniques for optimizing Python code. The code in question is '''an implementation of'''' the Soundex algorithm.''<
> 谨记着这些忠告,让我们来看一些优化 Python 代码的技术。我们要研究的代码是'''实施 Soundex 算法'''。<
> (./) 我们要研究的代码是 '''Soundex 算法的实现'''。 == 18.2 使用 timeit 模块 == 1. `Para -2`:Python 有一个方便的 min 函数'''可以把输入的列表返回成最小值''':<
> (./) Python 有一个方便的 min 函数'''返回输入列表中的最小值''': 1. `Para -1`:如果你有一个很大的 Python 程序并且不知道你的性能问题所在,'''到''' {X} 查看 hotshot 模块。 == 18.3 优化正则表达式 == 1. `Para 1`:''Regular expressions are almost never the right answer; they should be avoided whenever possible. Not only for performance reasons, but simply because they're difficult to '''debug''' and maintain.'' 正则表达式几乎永远不是最好的答案,而且应该被尽可能避开。这不仅仅是基于性能考虑,而是因为'''差错''' 和维护都很困难,…… (./) '''调试''' 1. `Para 4`:''How does soundex1a.py perform? For convenience, the `__main__` section of the script contains this code that calls the timeit module, sets up a timing test with three different names, tests each name three times, and displays the minimum time for each:''<
> soundex1a.py 表现如何?为了方便,`__main__` '''部分的代码包含了调用 timeit 模块,建立一个分别测试三个不同名字三次并显示最短耗时的一个计时测试代码''':<
> (./) soundex1a.py 表现如何?为了方便,`__main__` '''部分包含了一段代码:调用 timeit 模块,为三个不同名字分别建立测试,依次测试,并显示每个测试的最短耗时''': 1. `Para 7`:Woo 是个……小样本;Pilgrim 是个……正常样本;Flingjingwaller 是……特别长的样本。其它的测试可能同样有帮助,'''但它们已经是很好的不同样本范围了'''。<
> (./) 但它们已经'''很好地代表'''了不同的样本范围。 1. `Para -7`:''But is this the wrong path? The logic here is simple: the input source needs to be non-empty, and it needs to be composed entirely of letters. Wouldn't it be faster to write a loop checking each character, and '''do away with''' regular expressions altogether?'' 但是这样的优化是正路吗?这里的逻辑很简单:输入 source 应该是非空,并且需要完全由字母构成。如果编写一个循环查看每个字符'''并且与正则表达式一同工作'''是否会更快些? (./) 如果编写一个循环查看每个字符'''并且抛弃正则表达式''',是否会更快些? == 18.4 优化字典查找 == `pass` == 18.5 优化列表操作 == 1. `Para 6`:''soundex3a.py does not run any faster than soundex2c.py, and '''may''' even be slightly slower (although it's not enough of a difference to say for sure):''<
> soundex3a.py 并不比 soundex2c.py 运行得快 {i} ^多少^,而且甚至 {i} ^可能会^更慢些(差异还没有大到可以确信这一点):<
> (./) 有趣的是,结果表明 soundex3a.py 并不比 soundex2c.py 慢 (快那么一点点),不这样加就说不同了。 1. `Para 7`:为什么 soundex3a.py 不更快呢?其实 Python 的索引功能恰恰很有效。重复使用 digits2[-1] 根本没什么问题。另一方面,'''手工另外保留上一个数字为另外的变量'''意味着我们存储的每个数字的 两个 变量赋值,这便抹杀了我们避开索引查找所带来的微小好处。<
> (./) 另一方面,手工保留上一个数字意味着'''我们每存储一个数字都要为 两个 变量赋值'''…… 1. `Para -4`:'' Instead of incrementally building a new list (or string) out of the source string, why not move elements around within a single list?'' 与其一砖一瓦地建造一个新的列表(或者字符串),为什么不'''在一个列表中移动元素'''?<
> (./) 其一砖一瓦地建造一个新的列表(或者字符串),为什么不'''选择操作列表的元素呢'''?<
> (!) 就下文使用的方法来看,''move around'' 指的仅仅是一般意义的“改动”,而不是“移动”。 1. `Para -1`:我们在这儿除了试用了几种 “'''clever''' ” 的技术,根本没有什么进步。 (./) '''聪明''' == 18.6 优化字符串操作 == 1. `Para -5`:我们早就知道我们需要把结果截成四字符,并且我们知道我们'''已经有了一个没有改变的字符(起始字符从 source 中不作改变的拿过来)'''。这意味着我们可以仅仅在输出的结尾添加三个零,然后'''截短'''它。<
> (./) 我们早就知道我们需要把结果截成四字符,并且我们知道我们'''已经有了至少一个字符(直接从 source 中拿过来的起始字符)'''。这意味着我们可以仅仅在输出的结尾添加三个零,然后'''截断'''它。 == 18.7 小结 == 1. `Para -1`:最后一点太重要了,这章中你令这个程序'''三倍的提速'''并且另百万次的调用节省 20 秒。<
> (./) 最后一点太重要了,这章中你令这个程序'''提速三倍'''并且令百万次的调用节省 20 秒。