专栏首页BrianPython 性能分析

Python 性能分析

Python性能分析与优化

一个优秀的程序员,在保证业务正常的条件下都会追求自己的程序更快、更省。更快:运行时间短;更省:相对节省计算机资源(比如:CPU、Memory)。一般都是以这两种衡量方式来度量自己的程序及进一步优化自己程序的空间。更专业的性能分析软件一般有两类方法论:event-based profiling和statistical profiling

Event-based Profiling

并不是所有编程语言都支持这类性能分析,支持这类分析的语言主要有:

  • Java:JVMTI(JVM Tools Interface,JVM工具接口)为性能提供了钩子,可以跟踪函数调用和事件执行等等。
  • .NET :也提供了事件监听器,主要得益于.net 运行时。
  • Python:可以利用sys.setprofile函数来跟踪函数python(call,return,exception)或者c(call,return,exception).

基于事件的性能分析(event-based profiler or tracing profiler)是通过手机程序执行过程中的具体事件进行工作的,这些性能分析会产生大量的数据,基本而言,你监听的事件越多产生的数据量句越多。这导致它们不太实用,在开始对程序进行性能往往不是首选,当其他性能分析不够用或者不精准它们可以作为最后的选择。我们看一下一个python的例子:

Statistical Profiling

以固定的事件间隔对程序计数器进行抽样统计,可以查看每个函数的消耗时间。由于它对程序计数器进行抽样,所以数据结果是对真实值的统计近似。以便于查看分析程序的性能细节,查出性能瓶颈。

  • 分析的数据更少:只对程序执行过程进行抽样,而不用保留每一条数据。
  • 对性能造成的影响小:由于使用抽样(操作系统中断),目标程序的性能遭受干扰更小;虽然不能做到100%无干扰,但是要比基于事件的分析造成的干扰更小。

Python性能分析

现在我们来谈谈Python的性能分析,Python性能分析有很多工具和模块。比如:time粗粒度分析、cProfile,line_Profile等等。

time分析器

time.time()简单的衡量运行时间,我们看一下Demo:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import time

class Timer(object):
    def __init__(self):
        pass

    def __enter__(self):
        self.start = time.time()
        return self

    def __exit__(self, *args):
        self.end = time.time()
        self.secs = self.end - self.start
        print 'costed time: %f ms' % (self.secs * 1000)

def test():
    k = []
    for i in range(1000000):
        k.append(i**2+1000)
    return k
        
if __name__ == "__main__":
    with Timer() as t:
        test()
#运行结果:
costed time: 776.966095 ms

将要测量时间的代码用Python关键字with和Timer上下文管理器包起来。它会在你的代码运行的时候开始计时,并且在执行结束的完成计时。

性能分析器cProfile

cProfile是Python默认的性能分析器,它是一种确定性的性能分析器,提供了一组API来帮助开发者手机Python程序运行的信息。统计每个函数消耗的CPU时间,它只测量CPU时间,并不关心内存消耗和其他内存相关信息统计。

import cProfile
import pstats

def get_result():
    sum = 0
    for i in range(10000):
        sum += add_result(i,i+1)
    return sum

def add_result(a,b):
    return a+b
  
if __name__ == "__main__":
    cProfile.run("get_result()")
#结果如下:
         10004 function calls in 0.018 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.018    0.018 <string>:1(<module>)
    10000    0.006    0.000    0.006    0.000 untitled-1.py:10(add_result)
        1    0.011    0.011    0.018    0.018 untitled-1.py:4(get_result)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {range}

1004代表一共函数调用,花费了0.018秒,第一列ncalls代表了函数总共调用次数,第二列tottime总共运行时间,它不包括内部其它函数运行的时间,第三列cumtime函数总计运行时间,含调用的函数运行时间,tottime和cumtime是不一样的。可以这样理解:get_result花费时间等于tottime(get_result)+cumtime(add_result)最后一列比显示调用函数名。这是最常用的用法,cprofile也提供很多API,比如:查看函数调用了那些函数等等。

性能分析器line_Profile

这个是耕细粒度的性能分析,这个分析一行一行函数分析,不过得需要装饰器注册@profile然后还得需要kernprof脚本将会在执行的时候将它自动地注入到你的脚步的运行时。下面我们来看一下例子:

import cProfile
import pstats

@profile
def get_result():
    sum = 0
    for i in range(10000):
        sum += add_result(i,i+1)
    return sum

def add_result(a,b):
    return a+b
  
if __name__ == "__main__":
    get_result()

我们需要通过kernprof运行这个脚本,如下所示:
kernprof -l -v untitled-1.py
-l选项通知kernprof注入@profile装饰器到你的脚步的内建函数,-v选项通知kernprof在脚本执行完毕的时候显示计时信息。分析如下所示:
rote profile results to untitled-1.py.lprof
Timer unit: 1e-06 s

Total time: 0.008289 s
File: untitled-1.py
Function: get_result at line 4

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     4                                           @profile
     5                                           def get_result():
     6         1            2      2.0      0.0      sum = 0
     7     10001         2854      0.3     34.4      for i in range(10000):
     8     10000         5433      0.5     65.5          sum += add_result(i,i+1)
     9         1            0      0.0      0.0      return sum

这个很好理解,无需解释了。在下一个篇博客中,分析Python内存使用和如何查找内存溢出。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • AWK 深入浅出教程

    ---- 概述 awk是一门解释性文本处理语言,它在文本处理领域中非常强大和方便。awk有三个主要的类型是: AWK - 原先来源于 AT & T 实验室的的A...

    BrianLv
  • Python 多线程的同步方法

    ---- 概述 这篇博客是我翻译Python threads synchronization: Locks, RLocks, Semaphores, Condi...

    BrianLv
  • Python Data Model

    概述 最近在看《Fluent Python》一书,书中解释了Python很多重要的设计理念和实践,下面是我在看此书的读书笔记。Python的设计思想主要体现在它...

    BrianLv
  • 基于H7的中移动物联例子以及简易操作说明,方便电脑端和手机端远程查看数据

    说明: 1、操作前,务必优先看此贴里面的基础例子,先将WIFI连接到路由器上,这样才可以访问外网: https://www.cnblogs.com/armf...

    armfly
  • 动态 | 百度NLP团队登顶微软MARCO阅读理解测试

    AI 科技评论消息,2 月 21 日,百度 NLP 团队提交的 V-Net 模型以 46.15 的 Rouge-L 得分位列微软的 MS MARCO 机器阅读理...

    AI科技评论
  • 微软Build 2019大会来了!跨空间多人协作亮相;对话小娜如同真人

    一年一度的Microsoft Build 2019终于来了!大会于今日正式在美国西雅图拉开了帷幕。

    AiTechYun
  • 特写 | 「保持中立」的Yoshua Bengio,是如何被沈向洋引向微软的?

    选自Wired 作者:Jessi Hempel 参与:李泽南、李亚洲 在萨提亚·纳德拉掌权之后,微软正在沈向洋、Yoshua Bengio 等人的帮助下迅速成为...

    机器之心
  • Mapbox宣布开发新版SDK,可开发AR导航APP

    开源地图服务商Mapbox宣布,开发了一个新的软件开发工具包(SDK),可以让开发人员开发增强现实(AR)导航的应用程序。该SDK还能够使用ARM的Projec...

    BestSDK
  • Python读书笔记17(while与列表、字典)

    今天分享利用while函数处理列表和字典,顺便温习一下历史知识 一、论如何将一个列表折腾至另外一个列表!(两个列表是独立的) 论折腾列表有几种方法! 先分...

    用户1332619
  • IOWait高的一些处理方法

    IOWait高的一些处理方法 1、检查RAID的状态,比如是否正在重建或者没有初始化 2、替换操作系统的内核,最好使用发行版标准的Linux kernel,因...

    一见

扫码关注云+社区

领取腾讯云代金券