热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

《Python高性能编程》——2.4计时的简单方法——打印和修饰

本节书摘来自异步社区《Python高性能编程》一书中的第2章,第2.4节,作者[美]戈雷利克(MichaGorelick)&

本节书摘来自异步社区《Python高性能编程》一书中的第2章,第2.4节,作者[美] 戈雷利克 (Micha Gorelick),胡世杰,徐旭彬 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.4 计时的简单方法——打印和修饰

运行例2-4,我们看到的输出是由代码中几句print语句生成的。在Ian的笔记本上用CPython 2.7跑这段代码要花大约12秒。运行时间一般都会有一些波动。你必须在计时的同时观察这些正常的变化,否则你可能会误把某个随机的运行时间的变化当作是由于某次代码的改进造成的。

你的计算机在运行你的代码时还会进行其他任务,比如访问网络、磁盘或RAM,这些因素都会导致程序运行时间的变化。

Ian的笔记本是一台Dell E6420,拥有一个Intel Core I7-2720QM的CPU(2.20GHz,6MB缓存,4核)以及8GB的RAM,操作系统是Ubuntu 13.10。

在calc_pure_python中(例2-2),我们能看到一些print语句。这是最简单的在函数内部测量一段代码执行时间的方法。这个基本方法既快且脏,是在你刚开始着手调查代码时非常有用的手段。

在代码除错和性能分析上使用print语句是常用的手段。虽然它很快就会变得无法管理,但适用于简短的调查。用完它们以后要记得收拾干净,否则它们会搞乱你的stdout。

一个稍微干净一点的方法是使用修饰器——在需要调查的函数上面增加一行代码。我们的修饰器十分简单,仅仅复制了print语句的功能。后面我们会让它变得更加高级。

在例2-5中,我们定义了一个新函数timefn,它以一个函数fn为参数。它的内嵌函数measure_time接受args(数量可变的位置参数)以及*kwargs(数量可变的键值对参数)等参数并将其传入fn执行。在执行fn前后,我们抓取time.time()并将结果和fn.func_name一起打印出来。使用这个修饰器的开销很小,但如果你调用上千万次fn,开销就会变得引人注意。我们用@wraps(fn)将函数名和docstring暴露给fn的调用者(否则调用者看到的将是修饰器自身的函数名和docstring,而不是被修饰的函数的)。

例2-5 定义一个修饰器来自动测量时间

from functools import wrapsdef timefn(fn):@wraps(fn)def measure_time(*args, **kwargs):t1 = time.time()result = fn(*args, **kwargs)t2 = time.time()print ("@timefn:" + fn.func_name + " took " + str(t2 - t1) + " seconds")return resultreturn measure_time@timefn
def calculate_z_serial_purepython(maxiter, zs, cs):...

当我们运行这个版本的代码时(之前的print语句依然保留),我们会看到修饰器打印的执行时间要略快于calc_pure_python打印的时间。这是由于函数的调用带来了额外开销(差异非常小):

Length of x: 1000
Total elements: 1000000
@timefn:calculate_z_serial_purepython took 12.2218790054 seconds
calculate_z_serial_purepython took 12.2219250043 seconds

 备忘 额外的分析信息不可避免地降低了代码的执行速度——某些性能分析选项非常详细以至于带来了巨大的性能代价。分析信息的细节程度和运行速度是你必须要进行权衡的。

我们可以用timeit模块作为另一种测量执行速度的方法。通常来说,你会在解决问题的过程中用它来为各种简单的语句计时。

 警告  注意,timeit模块暂时禁用了垃圾收集器。如果你的操作会调用到垃圾收集器,那么它有可能影响到你实际操作的速度。更多信息请参见Python文档:http://bit.ly/timeit_doc。

你可以从命令行运行timeit如下:

$ python -m timeit -n 5 -r 5 -s "import julia1""julia1.calc_pure_python(desired_width=1000,max_iterations=300)"

注意你必须以-s命令在设置阶段导入julia1模块,因为calc_pure_python来自那个模块。timeit有一些合理的默认值适用于一段简短的代码,但对于要长期运行的代码来说,最好指定循环次数(-n 5)以及重复次数(-r 5)。timeit会对语句循环执行n次并计算平均值作为一个结果,重复r次并选出最好的那个结果。

如果我们不指定-n和-r运行timeit,默认是循环10次重复5次,需要6分钟。改变默认值可以让你更快获得结果。

我们只关注最好的那个结果,平均值以及最差结果可能是由于其他进程的影响。选择循环5次重复5次应该能给我们一个较为公正的结果:

5 loops, best of 5: 13.1 sec per loop

试着多运行几次,看看我们会不会得到不同的结果——你可能需要更多的重复次数来获得一个稳定的最佳结果时间。在这一点上不存在“正确”的配置,所以如果你发现你的计时结果变动范围很广,你就要选择更高的重复次数,直到获得稳定的最终结果。

我们的结果显示调用calc_pure_python的总体开销是13.1秒(最佳情况),而@timefn修饰器测算的单次调用calculate_z_serial_purepython耗时12.2秒。中间的差别主要是用于创建zs和cs列表的时间。

在IPython内部,我们可以用同样的方式使用%timeit魔法函数。如果你在IPython中用互动的方式开发你的代码且函数在本地名字空间(可能是因为你正在使用%run),那么你可以用:

%timeit calc_pure_python(desired_width=1000, max_iterations=300)

还有一点值得考虑的是一台计算机上的负载变化。很多后台运行的任务(如Dropbox、备份等)都会随机影响CPU和磁盘资源。网页上的脚本也会导致不可预测的资源使用。图2-4显示了我们刚刚进行的计时过程中某个CPU的使用率达到了100%,机器中的其他核心都在轻松处理其他的任务。


screenshot

系统监视器会时不时地显示这台机器上的活动峰值。有必要检查会不会有其他事件发生影响了你的关键资源(CPU、磁盘、网络)。



推荐阅读
  • 非公版RTX 3080显卡的革新与亮点
    本文深入探讨了图形显卡的进化历程,重点介绍了非公版RTX 3080显卡的技术特点和创新设计。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • pypy 真的能让 Python 比 C 还快么?
    作者:肖恩顿来源:游戏不存在最近“pypy为什么能让python比c还快”刷屏了,原文讲的内容偏理论,干货比较少。我们可以再深入一点点,了解pypy的真相。正式开始之前,多唠叨两句 ... [详细]
  • 关于进程的复习:#管道#数据的共享Managerdictlist#进程池#cpu个数1#retmap(func,iterable)#异步自带close和join#所有 ... [详细]
  • Python,英国发音:ˈpaɪθən,美国发音:ˈpaɪθ��ːn,空耳读法为“ ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了python3变量理解解释器理解常量理解用户交互理解相关的知识,希望对你有一定的参考价值。解释器理解 ... [详细]
  • golang常用库:配置文件解析库/管理工具viper使用
    golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ... [详细]
  • Docker的安全基准
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 深入理解Java中的volatile、内存屏障与CPU指令
    本文详细探讨了Java中volatile关键字的作用机制,以及其与内存屏障和CPU指令之间的关系。通过具体示例和专业解析,帮助读者更好地理解多线程编程中的同步问题。 ... [详细]
  • 在处理大规模并发请求时,传统的多线程或多进程模型往往无法有效解决性能瓶颈问题。尽管它们在处理小规模任务时能提升效率,但在高并发场景下,系统资源的过度消耗和上下文切换的开销会显著降低整体性能。相比之下,Python 的 `asyncio` 模块通过协程提供了一种轻量级且高效的并发解决方案。本文将深入解析 `asyncio` 模块的原理及其在实际应用中的优化技巧,帮助开发者更好地利用协程技术提升程序性能。 ... [详细]
  • 在Python中,可以通过导入 `this` 模块来优雅地展示“Python之禅”这一编程哲学。该模块会将这些指导原则以一种美观的方式输出到控制台。为了增加趣味性,可以考虑在代码中对输出内容进行简单的加密或混淆处理,以提升用户体验。 ... [详细]
  • 在Python编程中,当遇到程序运行无响应的问题时,通常与计算资源的消耗有关。Python使用任意精度整数进行计算,这意味着在处理大数值运算时,如计算大指数值,系统可能会因为内存或CPU资源不足而变得缓慢,甚至没有反馈。此外,代码中的无限循环或递归调用也可能导致类似问题。建议检查代码逻辑,优化算法效率,并确保计算任务不会超出系统的处理能力。 ... [详细]
  • 提升Python多环境管理效率:深入探索多Python Pip应用策略
    提升Python多环境管理效率:深入探索多Python Pip应用策略 ... [详细]
  • 为什么python是动态类型语言_Python 3.7.0 面向对象的动态类型语言
    代表Python开发社区和Python3.7发布团队,我们很高兴地宣布https:www.python.orgdownloadsreleasepython-370 ... [详细]
author-avatar
Y死一般的痛过
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有