《Python高性能编程》——2.4 计时的简单方法——打印和修饰-阿里云开发者社区

开发者社区> 异步社区> 正文

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

简介:
+关注继续查看

本节书摘来自异步社区《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 wraps

def 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 result
    return 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、磁盘、网络)。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
优秀API的设计原则与实例实现RESTful(1)
优秀API的设计原则与实例实现RESTful(1)
4 0
12306抢票神器,助力远在他乡想回家的你
每逢佳节倍思亲,年关将近,思乡的情绪是不是愈发强烈了,筒子们是不是又要准备开始抢票了,还是在找黄牛吗?但是,今年在考虑是否能抢到票以外,还需要考虑是否能回得去,没错,因为疫情,需要全国人民同心协力抗疫,咱不能给祖国妈妈添麻烦,只希望皆大欢喜吧!
11 0
ResNet实战:tensorflow2.X版本,ResNet50图像分类任务(大数据集)
本例提取了猫狗大战数据集中的部分数据做数据集,演示tensorflow2.X版本如何使用Keras实现图像分类,分类的模型使用ResNet50。本文实现的算法有一下几个特点: 1、自定义了图片加载方式,更加灵活高效,不用将图片一次性加载到内存中,节省内存,适合大规模数据集。 2、加载模型的预训练权重,训练时间更短。 3、数据增强选用albumentations。
7 0
ResNet实战:tensorflow2.X版本,ResNet50图像分类任务(小数据集)
本例提取了植物幼苗数据集中的部分数据做数据集,数据集共有12种类别,今天我和大家一起实现tensorflow2.X版本图像分类任务,分类的模型使用ResNet50。 通过这篇文章你可以学到: 1、如何加载图片数据,并处理数据。 2、如果将标签转为onehot编码 3、如何使用数据增强。 4、如何使用mixup。 5、如何切分数据集。 6、如何加载预训练模型。
5 0
InceptionV3实战:tensorflow2.X版本,InceptionV3图像分类任务(大数据集)
本例提取了猫狗大战数据集中的部分数据做数据集,演示tensorflow2.X版本如何使用Keras实现图像分类,分类的模型使用InceptionV3。本文实现的算法有一下几个特点: 1、自定义了图片加载方式,更加灵活高效,不用将图片一次性加载到内存中,节省内存,适合大规模数据集。 2、加载模型的预训练权重,训练时间更短。 3、数据增强选用albumentations。
9 0
centos 安装python2.7版本
centos 安装python2.7版本
12 0
深度剖析Saga分布式事务
saga是分布式事务领域非常重要的事务模式,特别适合解决旅游订票等长期事务。本文将深入分析saga事务的设计原理和解决订票问题的最佳实践。
7 0
9 个爱不释手的 JSON 工具
众所周知,JSON让开发人员易于使用,又让机器易于解析和生成。 JSON吸引了工具构建者的注意,它们开发了用于重新格式化、验证和解析JSON的众多工具,这不足为奇。这些工具既有在Web浏览器中运行的在线实用程序,又有面向代码编辑器和IDE的插件,比如Visual Studio Code和Eclipse。
6 0
+关注
异步社区
异步社区(www.epubit.com)是人民邮电出版社旗下IT专业图书旗舰社区,也是国内领先的IT专业图书社区,致力于优质学习内容的出版和分享,实现了纸书电子书的同步上架,于2015年8月上线运营。公众号【异步图书】,每日赠送异步新书。
12049
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载