Python3之性能度量

timeit类

timeit.Timer

timeit.Timer.timeit方法

语法:timeit.Timer(str_1 , str_2).timeit(intvalue)
参数说明:
str_1 :字符串类型,为传入需要计时的语句或者函数,即:“执行语句"或"函数名()”
str_2:字符串类型,为传入第一个参数语句构建环境的导入语句。此时 timeit 构建起一个独立的虚拟环境, 手工地执行建立语句,然后手工地编译和执行被计时语句。即:"from main import 函数名"
intvalue:整型,为测试过程中被计时语句或函数执行的次数,默认为一百万次;返回所耗费的秒数

# timeit.Timer类计时

import timeit

def fun_1():
    sum = 0
    for i in range(10000):
        sum += i
    return sum

def fun_2():
    sum = 0
    for i in range(100000):
        sum += i
    return sum

# 1、timeit.Timer.timeit()计时
# 使用timeit.Timer.timeit()计时,执行fun_1函数10000次,返回结果为秒
time_1 = timeit.Timer("fun_1()" , "from __main__ import fun_1").timeit(10000)
print("timeit.Timer.timeit()计时fun_1:" , time_1)
time_2 = timeit.Timer("fun_2()" , "from __main__ import fun_2").timeit(1000)
print("timeit.Timer.timeit()计时fun_2:" , time_2)
timeit.Timer.timeit()计时fun_1: 5.977923
timeit.Timer.timeit()计时fun_2: 6.3918026999999995
timeit.Timer.repeat方法

语法:timeit.Timer(str_1 , str_2).repect(intvalue_1 , intvalue_2)
参数说明:
str_1 :字符串类型,为传入需要计时的语句或者函数,即:“执行语句"或"函数名()”
str_2:字符串类型,为传入第一个参数语句构建环境的导入语句。此时 timeit 构建起一个独立的虚拟环境, 手工地执行建立语句,然后手工地编译和执行被计时语句。即:"from main import 函数名"
intvalue_1:整型,整个测试重复的次数,默认为3
intvalue_2:整型,为测试过程中被计时语句或函数执行的次数,默认为一百万次;repeat() 方法返回以秒记录的每个测试循环的耗时列表。Python 中的 max、min 函数可以把输入的列表返回成最大、最小值,如: min(timeit.Timer(str_1 , str_2).repeat(3, 1000000))

# timeit.Timer类计时

import timeit

def fun_1():
    sum = 0
    for i in range(10000):
        sum += i
    return sum

def fun_2():
    sum = 0
    for i in range(100000):
        sum += i
    return sum
# 2、timeit.Timer.repect()计时
time_3 = timeit.Timer( "fun_1()" , "from __main__ import fun_1" ).repeat(3 , 10000)
print("timeit.Timer.repect()计时fun_1:" , time_3 , "max:" , max(time_3) , "mix:" , min(time_3))
timeit.Timer.repect()计时fun_1: [6.379943000000001, 5.9786114999999995, 6.348257100000001] max: 6.379943000000001 mix: 5.9786114999999995

timeit.timeit

timeit模块源码为:

def timeit(stmt="pass", setup="pass", timer=default_timer,
           number=default_number):
    """Convenience function to create Timer object and call timeit method."""
    return Timer(stmt, setup, timer).timeit(number)
 
def repeat(stmt="pass", setup="pass", timer=default_timer,
           repeat=default_repeat, number=default_number):
    """Convenience function to create Timer object and call repeat method."""
    return Timer(stmt, setup, timer).repeat(repeat, number)

参数说明:
stmt:这个参数就是statement,即需要计时的语句或者函数,可以直接接受字符串的表达式,也可以接受单个变量,还可以接受函数;
setup: 这个参数可以传入第一个参数语句构建环境的导入语句;
timer:这个参数一般使用不到,默认可不填;

timeit 类下面也有 repeat 和 timeit 方法,使用方法为 timeit.timeit 和 timeit.repeat

timeit.timeit方法

语法:timeit.timeit(stmt="pass", setup="pass", timer=default_timer, number=default_number)
参数说明:
stmt:statement,即需要计时的语句或者函数,可以直接接受字符串的表达式,也可以接受单个变量,还可以接受函数;
setup: 这个参数可以传入第一个参数语句构建环境的导入语句;
timer:这个参数一般使用不到,默认可不填;
number:整型,为测试过程中被计时语句或函数执行的次数,默认为一百万次;返回所耗费的秒数

# timeit.timeit类

import timeit

def fun_1():
    sum = 0
    for i in range(10000):
        sum += i
    return sum

def fun_2():
    sum = 0
    for i in range(100000):
        sum += i
    return sum

# 1、timeit.timeit()计时
# 使用timeit.timeit()计时,执行fun_1函数10000次,返回结果为秒
time_1 = timeit.timeit(stmt = "fun_1()" , setup="from __main__ import fun_1" , number=10000)
print("timeit.timeit()计时fun_1:" , time_1)
time_2 = timeit.timeit(stmt = "fun_2()" , setup="from __main__ import fun_2" , number=1000)
print("timeit.timeit()计时fun_2:" , time_2)
timeit.timeit()计时fun_1: 5.9416145
timeit.timeit()计时fun_2: 6.0575809
timeit.repect方法

语法:repeat(stmt="pass", setup="pass", timer=default_timer, repeat=default_repeat, number=default_number)
参数说明:
stmt:statement,即需要计时的语句或者函数,可以直接接受字符串的表达式,也可以接受单个变量,还可以接受函数;
setup: 这个参数可以传入第一个参数语句构建环境的导入语句;
timer:这个参数一般使用不到,默认可不填;
number:整型,为测试过程中被计时语句或函数执行的次数,默认为一百万次;返回所耗费的秒数
repeat:整型,整个测试重复的次数,默认为3

# timeit.timeit类

import timeit

def fun_1():
    sum = 0
    for i in range(10000):
        sum += i
    return sum

def fun_2():
    sum = 0
    for i in range(100000):
        sum += i
    return sum
# 2、timeit.repect()计时
time_3 = timeit.repeat(stmt= "fun_1()" , setup="from __main__ import fun_1" , repeat=10 , number=10000)
print("timeit.repect()计时fun_1:" , time_3 , "max:" , max(time_3) , "mix:" , min(time_3))
time_4 = timeit.repeat(stmt= "fun_2()" , setup="from __main__ import fun_2" , repeat=10 , number=1000)
print("timeit.repect()计时fun_2:" , time_4 , "max:" , max(time_4) , "mix:" , min(time_4))
timeit.timeit()计时fun_1: 6.05385
timeit.timeit()计时fun_2: 5.9594193
timeit.repect()计时fun_1: [6.1215308, 6.3348572999999995, 5.926046899999999] max: 6.3348572999999995 mix: 5.926046899999999
timeit.repect()计时fun_2: [6.573079199999999, 5.946404199999996, 6.233260800000004] max: 6.573079199999999 mix: 5.946404199999996

Profile类

   日常工作会遇到相同功能,使用不同的实现方式,代码执行效率不同问题,代码优化的前提是需要了解性能瓶颈在什么地方,程序运行的主要时间是消耗在哪里,python 内置了丰富的性能分析工具,如 profile、cProfile和hotshot 等。其中 Profiler 是 python 自带的性能分析工具,能够描述程序运行时的性能,并提供各种统计帮助用户定位程序的性能瓶颈。
   Python 标准模块提供了三种 profilers,分别为:cProfile、profile和hotshot
   profile 的使用较为简单,只需要在使用之前进行 import 即可,也可以在命令行中使用
1、profile类分析python代码
# 使用profile类分析代码性能

import profile

def fun_1():
    sum = 0
    for i in range(10000):
        sum += i
    return sum

def fun_2():
    sum = 0
    for i in range(10000):
        sum += fun_1() # fun_2()调用fun_1()
    return sum

def fun_3():
    sum = 0
    for i in range(10000):
        sum += fun_2() # fun_3()调用fun_2()
    return sum

if __name__ == "__main__":
    profile.run("fun_1()")
    profile.run("fun_2()")
    profile.run("fun_3()")
    profile.run("fun_1()" , "fun_1_result.txt" , "utf-8")
    profile.run("fun_2()" , "fun_2_result.txt" , "utf-8")
    profile.run("fun_3()" , "fun_3_result.txt" , "utf-8")
         5 function calls in 0.016 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 :0(exec)
        1    0.016    0.016    0.016    0.016 :0(setprofile)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 ZX_03_Profile.py:5(fun_1)
        1    0.000    0.000    0.016    0.016 profile:0(fun_1())
        0    0.000             0.000          profile:0(profiler)


         1005 function calls in 0.047 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.047    0.047 :0(exec)
        1    0.000    0.000    0.000    0.000 :0(setprofile)
        1    0.000    0.000    0.047    0.047 <string>:1(<module>)
        1    0.000    0.000    0.047    0.047 ZX_03_Profile.py:11(fun_2)
     1000    0.047    0.000    0.047    0.000 ZX_03_Profile.py:5(fun_1)
        1    0.000    0.000    0.047    0.047 profile:0(fun_2())
        0    0.000             0.000          profile:0(profiler)


         1001005 function calls in 59.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   59.000   59.000 :0(exec)
        1    0.000    0.000    0.000    0.000 :0(setprofile)
        1    0.000    0.000   59.000   59.000 <string>:1(<module>)
     1000    1.328    0.001   59.000    0.059 ZX_03_Profile.py:11(fun_2)
        1    0.000    0.000   59.000   59.000 ZX_03_Profile.py:17(fun_3)
  1000000   57.672    0.000   57.672    0.000 ZX_03_Profile.py:5(fun_1)
        1    0.000    0.000   59.000   59.000 profile:0(fun_3())
        0    0.000             0.000          profile:0(profiler)

参数说明:
ncalls:函数调用的次数
tottime:函数的总的运行时间,除掉函数中调用子函数的运行时间
percall:(第一个 percall)等于tottime / ncalls
cumtime:函数及其所有子函数的调用运行的时间,即函数开始调用到返回的时间
percall:(第二个 percall)即函数运行一次的平均时间,等于 cumtime / ncalls
filename:lineno(function):每个函数调用的具体信息

2、命令行分析python代码

test.py中代码如下:

# 使用命令行分析代码性能

import os

def fun_1():
    sum = 0
    for i in range(1000):
        sum += i
    return sum

def fun_2():
    sum = 0
    for i in range(1000):
        sum += fun_1() # fun_2()调用fun_1()
    return sum

def fun_3():
    sum = 0
    for i in range(1000):
        sum += fun_2() # fun_3()调用fun_2()
    return sum

print(fun_1())
print(fun_2())
print(fun_3())

1、运行命令查看性能分析结果:
python -m cProfile test.py

2、性能分析结果保存到result文件:
python -m cProfile -o result test.py

3、使用pstats来格式化显示结果:
python -c “import pstats; p=pstats.Stats('reslut); p.print_stats()”

python -c "import pstats; p=pstats.Stats(‘result’); p.sort_stats(‘time’).print_stats()

其中sort_stats支持如下参数:
calls、cumulative、file、line、module、name、nfl、pcalls、stdname、time

Pstats类

使用pstats类分析性能步骤:
1、使用profile.run()将分析结果保存至某个文件内
profile.run(“函数名()” , “xxx.txt”)
2、创建Stats对象
variable = pstats.Stats(“xxx.txt”)
3、使用pstats格式化输出分析结果
strip_dirs(): 去掉无关的路径信息

sort_stats(): 排序,支持的方式和上述的一致,即:calls、cumulative、file、line、module、name、nfl、pcalls、stdname、time

print_stats(): 打印分析结果,可以指定打印前几行

按照函数名排序,只打印前3行函数的信息,参数还可为小数,表示前百分之几的函数信息
p.strip_dirs().sort_stats(“name”).print_stats(3)

按照运行时间和函数名进行排序
p.strip_dirs().sort_stats(“cumulative”, “name”).print_stats(0.8)

如果想知道有哪些函数调用了bar
p.print_callers(“bar”)

查看test()函数中调用了哪些函数
p.print_callees(“foo”)

# 使用pstats库分析性能

import pstats , profile

def fun_1():
    sum = 0
    for i in range(1000):
        sum += i
    return sum

def fun_2():
    sum = 0
    for i in range(1000):
        sum += fun_1()
    return sum

def fun_3():
    sum = 0
    for i in range(1000):
        sum += fun_2()
    return sum

if __name__ == "__main__":

    # 将结果保存到result文件中
    profile.run("fun_3()" , "fun_1_pstats_result.txt")

    """
    使用 pstats 模块的代码
    """
    # 创建Stats对象
    p = pstats.Stats("fun_1_pstats_result.txt")

    # strip_dirs(): 去掉无关的路径信息
    # sort_stats(): 排序,支持的方式和上述的一致,
    # 即:calls、cumulative、file、line、module、name、nfl、pcalls、stdname、time
    # print_stats(): 打印分析结果,可以指定打印前几行

    # 按照函数名排序,只打印前3行函数的信息
    p.strip_dirs().sort_stats("name").print_stats(3)

    # 按照运行时间和函数名进行排序
    p.strip_dirs().sort_stats("cumulative", "name").print_stats(0.8)

    # 哪些函数调用了fun_1
    p.print_callers("fun_1")

    # 查看fun_3()函数中调用了哪些函数
    p.print_callees("fun_3")
Mon Jun 15 23:11:14 2020    fun_1_pstats_result.txt

         1001005 function calls in 56.203 seconds

   Ordered by: function name
   List reduced from 8 to 3 due to restriction <3>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   56.203   56.203 <string>:1(<module>)
        1    0.000    0.000   56.203   56.203 :0(exec)
  1000000   54.984    0.000   54.984    0.000 ZX_05_Profile_pstats库.py:5(fun_1)


Mon Jun 15 23:11:14 2020    fun_1_pstats_result.txt

         1001005 function calls in 56.203 seconds

   Ordered by: cumulative time, function name
   List reduced from 8 to 6 due to restriction <0.8>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   56.203   56.203 <string>:1(<module>)
        1    0.000    0.000   56.203   56.203 :0(exec)
     1000    1.219    0.001   56.203    0.056 ZX_05_Profile_pstats库.py:11(fun_2)
        1    0.000    0.000   56.203   56.203 ZX_05_Profile_pstats库.py:17(fun_3)
        1    0.000    0.000   56.203   56.203 profile:0(fun_3())
  1000000   54.984    0.000   54.984    0.000 ZX_05_Profile_pstats库.py:5(fun_1)


   Ordered by: cumulative time, function name
   List reduced from 8 to 1 due to restriction <'fun_1'>

Function                           was called by...
ZX_05_Profile_pstats库.py:5(fun_1)  <- ZX_05_Profile_pstats库.py:11(fun_2)(1000000)   56.203


   Ordered by: cumulative time, function name
   List reduced from 8 to 2 due to restriction <'fun_3'>

Function                            called...
ZX_05_Profile_pstats库.py:17(fun_3)  -> ZX_05_Profile_pstats库.py:11(fun_2)(1000)   56.203
profile:0(fun_3())                  -> :0(exec)(1)   56.203
                                       :0(setprofile)(1)    0.000
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值