第 21 章 标杆插曲
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
既然我们已经了解了编码函数和迭代工具,那么我们就来一次短途旅行,让它们都派上用场。本章以一个更大的案例研究结束本书的函数部分,该案例研究了我们迄今为止遇到的迭代工具的相对性能。
一路上,本案例研究调查了 Python 的代码计时工具,讨论了一般的基准测试技术,并允许我们探索比我们到目前为止所看到的大多数代码更真实、更有用的代码。我们还将测量当前 Python 实现的速度--这个数据点可能重要,也可能不重要,这取决于您编写的代码类型。
最后,由于这是本书这一部分的最后一章,我们将以常见的 "疑难解答 "和练习来结束,以帮助你开始编码你所读到的想法。不过,首先让我们来体验一下 Python 应用程序的乐趣。
定时迭代替代方案
在本书中,我们遇到了很多 迭代替代方案。就像编程中的许多事情一样,它们代表着折衷--既有主观因素(如表现力),也有更客观的标准(如性能)。作为程序员和工程师,你的工作之一就是根据这些因素来选择工具。
在性能方面,我曾多次提到,列表理解有时比for 循环语句更快,而map 调用根据调用模式的不同,可能比两者都快,也可能比两者都慢。上一章中的生成器函数和表达式往往比列表理解稍慢,尽管它们最大限度地减少了内存空间需求,并且在有许多结果需要生成时不会延迟调用者生成结果。
所有这些在今天一般都是正确的,但相对性能会随着时间的推移而变化,因为 Python 的内部结构在不断变化和优化,代码结构会任意影响速度。如果您想亲自验证它们的性能,就需要在自己的计算机和自己的 Python 版本上对这些替代方案进行计时。
定时模块:自制
幸运的是,Python 可以轻松地为代码计时。例如,如果要计算多次调用一个带有任意位置参数的函数所需的总时间,使用下面的首切函数就足够了:
# File timer0.pyimport time def timer(func, *args):# Simplistic timing functionstart = time.clock() for i in range(1000): func(*args) return time.clock() - start# Total elapsed time in seconds
这个方法很有效--它从 Python 的time 模块中获取时间值,,并在使用传入参数运行 1000 次传入函数调用后,从停止时间中减去系统开始时间。在我使用 Python 3.3 的电脑上:
>>>from timer0 import timer>>>timer(pow, 2, 1000)# Time to call pow(2, 1000) 1000 times0.00296260674205626 >>>timer(str.upper, 'spam')# Time to call 'spam'.upper() 1000 times0.0005165746166859719
这款计时器虽然简单,但也相当有限,在功能设计和基准测试方面都故意犯了一些典型错误。 其中包括:
在测试的函数调用中不支持关键字参数
硬编码重复次数
将
range的费用计入测试功能的时间总是使用
time.clock,在 Windows 以外可能不是最佳选择没有为调用者提供验证被测试函数是否真正起作用的方法
只提供总时间,在某些负载较重的机器上可能会出现波动
换句话说,定时代码比你想象的要复杂得多!为了更加概括和准确,让我们把它扩展到仍然简单但更有用的定时器实用函数中,我们既可以用它来查看现在的迭代替代选项是如何堆叠的,也可以在将来应用到其他定时需求中。这些函数被编码在一个模块文件中,因此它们可以在各种程序中使用,并且有 ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access