基准测试与性能分析

摘要:本文介绍了基准测试和性能分析在优化程序性能中的应用。基准测试通过对比标准评估代码执行速度,Python的timeit模块可用于测量代码耗时,也可通过装饰器自定义计时器。性能分析则测量内存、时间复杂度等属性,cProfile模块能记录所有函数调用及耗时情况,输出包含调用次数、总耗时等指标,帮助定位性能瓶颈。文章通过具体代码示例展示了timeit和cProfile的使用方法,为程序性能优化提供了实用工具和技术方案。

目录

基准测试与性能分析

什么是基准测试?

基准测试的工作原理

[Python 基准测试模块](#Python 基准测试模块)

示例

输出结果

利用装饰器自定义计时器

输出结果

什么是性能分析?

内置性能分析模块:cProfile

示例


基准测试与性能分析

在本章中,我们将学习基准测试和性能分析如何帮助解决程序性能问题。

假设我们编写的代码能输出预期结果,但随着需求变化,希望让代码运行得更快。这时我们需要找出拖慢整个程序运行速度的代码段,而基准测试和性能分析就能发挥作用。

什么是基准测试?

基准测试的核心是通过与标准对比来评估事物的性能。而在软件编程中,我们需要明确:编程中的基准测试指什么,又为何需要它?代码的基准测试,是检测代码的执行速度,定位性能瓶颈所在。开展基准测试的一个重要目的,就是对代码进行性能优化。

基准测试的工作原理

谈及基准测试的执行逻辑,首先需要对整个程序的当前运行状态做一次整体基准测试,随后结合微基准测试,将整个程序拆解为多个小程序模块。通过这种方式找出程序内部的性能瓶颈,进而开展优化工作。换句话说,这一过程就是把复杂的大问题拆解为一系列相对简单的小问题,再逐一进行优化。

Python 基准测试模块

Python 内置了专门用于基准测试的模块 ------timeit 。借助timeit模块,我们可以在主程序中测量小段 Python 代码的执行性能。

示例

在以下 Python 脚本中,我们导入timeit 模块,用于分别测量functionAfunctionB两个函数的执行耗时:

python 复制代码
import timeit
import time
def functionA():
 print("函数A开始执行:")
 print("函数A执行完成:")
def functionB():
 print("函数B开始执行")
 print("函数B执行完成")
start_time = timeit.default_timer()
functionA()
print(timeit.default_timer() - start_time)
start_time = timeit.default_timer()
functionB()
print(timeit.default_timer() - start_time)

运行上述脚本后,我们将得到两个函数的执行耗时,输出结果如下。

输出结果

plaintext

复制代码
函数A开始执行:
函数A执行完成:
0.0014599495514175942
函数B开始执行
函数B执行完成
0.0017024724827479076

利用装饰器自定义计时器

在 Python 中,我们可以自定义一个计时器,实现和timeit 模块相同的功能,这一需求可以通过装饰器函数来完成。以下是自定义计时器的示例:

python 复制代码
import random
import time

def timer_func(func):
 def function_timer(*args, **kwargs):
 start = time.time()
 value = func(*args, **kwargs)
 end = time.time()
 runtime = end - start
 msg = "函数{func}的执行耗时为{time}秒。"
 print(msg.format(func = func.__name__,time = runtime))
 return value
 return function_timer

@timer_func
def Myfunction():
 for x in range(5):
 sleep_time = random.choice(range(1,3))
 time.sleep(sleep_time)

if __name__ == '__main__':
 Myfunction()

上述 Python 脚本导入了 random 和 time 模块,我们定义了装饰器函数 timer_func (),该函数内部嵌套了 function_timer () 函数。这个嵌套函数会在调用传入的目标函数前记录开始时间,等待目标函数执行完毕后记录结束时间,最终让脚本打印出目标函数的执行耗时。脚本的输出结果如下。

输出结果

plaintext

复制代码
函数Myfunction的执行耗时为8.000457763671875秒。

什么是性能分析?

有时程序员需要测量程序的各项属性,比如内存占用、时间复杂度,或是特定指令的使用情况,以此评估程序的实际性能。这类对程序各项属性的测量行为,就是性能分析。性能分析通过动态程序分析技术来完成这些测量工作。

在后续的小节中,我们将学习用于性能分析的各类 Python 模块。

内置性能分析模块:cProfile

cProfile是 Python 的内置性能分析模块,该模块基于 C 语言扩展开发,运行开销合理,适合对长时间运行的程序做性能分析。运行该模块后,它会记录下程序中所有函数的调用情况及执行耗时。cProfile 功能强大,但有时其输出结果的解读和实际应用会有一定难度。以下是使用 cProfile 对一段代码做性能分析的示例:

示例

python 复制代码
def increment_global():
 global x
 x += 1

def taskofThread(lock):
 for _ in range(50000):
 lock.acquire()
 increment_global()
 lock.release()

def main():
 global x
 x = 0

 lock = threading.Lock()

 t1 = threading.Thread(target=taskofThread, args=(lock,))
 t2 = threading.Thread(target= taskofThread, args=(lock,))

 t1.start()
 t2.start()

 t1.join()
 t2.join()

if __name__ == "__main__":
 for i in range(5):
 main()
 print("第{0}次循环后,x = {1}".format(i,x))

将上述代码保存为thread_increment.py文件,随后在命令行中结合 cProfile 执行该文件,命令如下:

plaintext

复制代码
(base) D:\ProgramData>python -m cProfile thread_increment.py
第0次循环后,x = 100000
第1次循环后,x = 100000
第2次循环后,x = 100000
第3次循环后,x = 100000
第4次循环后,x = 100000
 3577次函数调用(其中3522次原生调用),总耗时1.688秒

 按标准名称排序

 调用次数    总耗时    单次耗时    累积耗时    单次累积耗时  文件名:行号(函数名)

 5        0.000      0.000      0.000      0.000 <frozen importlib._bootstrap>:103(release)
 5        0.000      0.000      0.000      0.000 <frozen importlib._bootstrap>:143(__init__)
 5        0.000      0.000      0.000      0.000 <frozen importlib._bootstrap>:147(__enter__)

从上述输出结果可以看出,cProfile 打印出了程序中全部 3577 次的函数调用记录,包含每个函数的耗时以及调用次数。输出结果中的各列含义如下:

  • ncalls(调用次数):函数被调用的总次数。
  • tottime(总耗时):在指定函数中执行所花费的总时间(不包含调用子函数的耗时)。
  • percall(单次耗时):总耗时除以调用次数的结果。
  • cumtime(累积耗时):在指定函数及其所有子函数中执行所花费的总时间,该指标对递归函数同样精准。
  • percall(单次累积耗时):累积耗时除以原生调用次数的结果。
  • filename:lineno (function)(文件名:行号 (函数名)):对应每个函数的文件、行号及函数名信息。
相关推荐
神仙别闹2 小时前
基于MATLAB实现(GUI)汽车出入库识别系统
开发语言·matlab·汽车
今儿敲了吗2 小时前
python基础学习笔记第一章
开发语言·python
witAI2 小时前
**GLM5剧本拆解2025指南,解锁多模态创作新范式**
人工智能·python
badhope2 小时前
C语言二级考点全解析与真题精讲
c语言·开发语言·c++·人工智能·python·microsoft·职场和发展
李昊哲小课2 小时前
NumPy 完整学习笔记
笔记·python·学习·数据分析·numpy
理性的曜2 小时前
AI语音通话系统设计思路:从语音输入到智能回复
人工智能·python·websocket·fastapi
专业发呆业余科研2 小时前
深度反思不变学习:当 EIIL 失效时,如何通过“偏见诱导”重建环境标签?
人工智能·python·深度学习·神经网络·机器学习
醉酒柴柴2 小时前
word创建样式以后应用于所有新文件
开发语言·学习·c#·word
董董灿是个攻城狮2 小时前
大模型连载8:词向量如何表示近义词?
人工智能·python·算法·机器学习