本节书摘来自异步社区《Python高性能编程》一书中的第2章,第2.14节,作者[美] 戈雷利克 (Micha Gorelick),胡世杰,徐旭彬 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。
2.14 确保性能分析成功的策略
性能分析需要一些时间和精力。如果你把需要测试的代码段跟你代码的主体分离,你会有一个更好的机会去了解你的代码。然后你可以用单元测试来保证正确性,你还可以传入精心编造的真实数据来测试算法的有效性。
记得关闭任何基于BIOS的加速器,因为它们只会混淆你的结果。Ian的笔记本电脑使用的Intel TurboBoost功能可以在温度足够低的时候将CPU暂时加至极速。这意味着低温时运行同一段代码的速度可能比高温时要快。你的操作系统也许还控制了时钟的速度——使用电池电源的笔记本可能比插了主电源时更积极地控制CPU的速度。为了建立一个更加稳定的测试配置,我们:
在BIOS上禁用了TurboBoost。
禁用了操作系统改写SpeedStep(如果你有权限,你可以在你的BIOS中找到它)的能力。
只使用主电源(从不使用电池电源)。
运行实验时禁用后台工具如备份和Dropbox。
多次运行实验来获得一个稳定的测量结果。
如果可能,降至run level 1(UNIX),确保没有其他任务运行。
重启并重跑实验来二次验证结果。
试着假设你代码的行为并用性能分析的结果来证实(或证伪)你的假设。你的选择不会改变(因为你的决定只能基于性能分析后的结果),但是你对代码的直觉了解会提升,而这会在今后的项目中带来好处,因为你会变得更能做出高效的决定。当然,你依然需要性能分析来验证这些高效的决定。
不要克扣准备工作。如果你在测试一段深入大型项目的代码前不先将代码分离,你很有可能会因为一些副作用而让你的努力偏离正轨。当你进行细粒度的改动时,对大型项目进行单元测试往往会更困难,而这又会更进一步妨碍你的努力。副作用可能包括其他线程或进程影响了CPU和内存的使用以及网络和磁盘的活动,这些都会歪曲你的结果。
对于Web服务器,推荐dowser和dozer;你可以用它们来将名字空间中的对象行为实时可视化。如果可能,一定要将你想测试的代码从Web应用的主体上分离出来,这会让性能分析方便太多。
确保你的单元测试覆盖了所有你想要分析的代码路径。任何你没有测过的东西都有可能带来细微的错误拖慢你的进度。使用coverage.py来确认你的测试覆盖了所有的代码路径。
对一个生成很多数字输出的复杂代码段进行单元测试可能会很困难。不要害怕将结果输出到一个文本文件来运行diff或者使用一个pickled对象。对于数字优化的问题,Ian喜欢创建一个包含了大量浮点数的长文本文件并使用diff——细小的取整问题会立刻显现,哪怕它们在输出中很罕见。
如果你的代码容易受到数字取整问题的影响,那么你最好有一个大的输出可以用来进行前后对比。取整错误的一个原因是CPU寄存器和主存之间的浮点精度不同。你的代码在不同的代码路径上运行可能导致细微的取整错误并在之后给你带来困扰——所以最好在它们刚发生的时候就尽早意识到这点。
显然,在性能分析和优化时使用源代码控制工具是很有意义的。创建新的代码分支代价很低,而且它能让你保持头脑清醒。