Python多线程

Python基准分析

Python基准分析详细操作教程
在本章中,我们将学习基准测试和性能分析如何帮助解决性能问题。
假设我们已经编写了一个代码,并且它也给出了预期的结果,但是如果由于需求发生了变化,我们希望更快地运行此代码,该怎么办。在这种情况下,我们需要找出代码的哪些部分使整个程序变慢。在这种情况下,基准测试和性能分析会很有用。

什么是基准测试?

基准测试旨在通过​​与标准比较来评估某些内容。但是,这里出现的问题是,基准测试是什么以及在软件编程的情况下为什么需要基准测试。对代码进行基准测试意味着代码执行速度有多快,瓶颈在哪里。进行基准测试的主要原因之一是它可以优化代码。

基准测试如何工作?

如果我们谈论基准测试的工作,我们需要先将整个程序作为一个当前状态进行基准测试,然后我们可以组合微基准测试,然后将程序分解为较小的程序。为了找到我们程序中的瓶颈并对其进行优化。换句话说,我们可以将其理解为将大而棘手的问题分解为一系列较小和较容易解决的问题,以对其进行优化。

用于基准测试的Python模块

在Python中,默认情况下,我们有一个基准测试模块,称为 timeit 。借助 timeit 模块,我们可以在主程序中测量少量Python代码的性能。

示例

在下面的Python脚本中,我们将导入 timeit 模块,该模块将进一步测量执行两个功能- functionA functionB -
# Filename : example.py
# Copyright : 2020 By Lidihuo
# Author by : www.lidihuo.com
# Date : 2020-08-22
import timeit
import time
def functionA():
   print("Function A starts the execution:")
   print("Function A completes the execution:")
def functionB():
   print("Function B starts the execution")
   print("Function B completes the execution")
start_time = timeit.default_timer()
functionA()
print(timeit.default_timer() - start_time)
start_time = timeit.default_timer()
functionB()
print(timeit.default_timer() - start_time)
运行上述脚本后,我们将获得两个函数的执行时间,如下所示。

输出

# Filename : example.py
# Copyright : 2020 By Lidihuo
# Author by : www.lidihuo.com
# Date : 2020-08-22
Function A starts the execution:
Function A completes the execution:
0.0014599495514175942
Function B starts the execution
Function B completes the execution
0.0017024724827479076

使用装饰器功能编写自己的计时器

在Python中,我们可以创建自己的计时器,其作用类似于 timeit 模块。可以在 decorator 函数的帮助下完成。以下是自定义计时器的示例-
# Filename : example.py
# Copyright : 2020 By Lidihuo
# Author by : www.lidihuo.com
# Date : 2020-08-22
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} took {time} seconds to complete its execution."
      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脚本有助于导入随机时间模块。我们已经创建了timer_func()装饰器函数。它内部具有function_timer()函数。现在,嵌套函数将在调用传入的函数之前抢占时间。然后,它等待函数返回并获取结束时间。这样,我们最终可以使python脚本打印执行时间。该脚本将生成如下所示的输出。

输出

# Filename : example.py
# Copyright : 2020 By Lidihuo
# Author by : www.lidihuo.com
# Date : 2020-08-22
Myfunction took 8.000457763671875 seconds to complete its execution.

什么是配置文件?

有时,程序员想衡量一些属性,例如内存使用,时间复杂性或有关程序的特定指令的使用,以衡量该程序的实际功能。这种关于程序的度量称为概要分析。概要分析使用动态程序分析来进行此类测量。
在随后的部分中,我们将学习用于分析的不同Python模块。

cProfile –内置模块

cProfile 是用于分析的Python内置模块。该模块是C扩展,具有合理的开销,使其适合于分析长时间运行的程序。运行后,它将记录所有功能和执行时间。它非常强大,但有时难以解释和采取行动。在下面的示例中,我们在下面的代码上使用cProfile-

示例

# Filename : example.py
# Copyright : 2020 By Lidihuo
# Author by : www.lidihuo.com
# Date : 2020-08-22
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("x = {1} after Iteration {0}".format(i,x))
上面的代码保存在 thread_increment.py 文件中。现在,在命令行上使用cProfile执行代码,如下所示:-
# Filename : example.py
# Copyright : 2020 By Lidihuo
# Author by : www.lidihuo.com
# Date : 2020-08-22
(base) D:\ProgramData>python -m cProfile thread_increment.py
x = 100000 after Iteration 0
x = 100000 after Iteration 1
x = 100000 after Iteration 2
x = 100000 after Iteration 3
x = 100000 after Iteration 4
      3577 function calls (3522 primitive calls) in 1.688 seconds
   Ordered by: standard name
   ncalls tottime percall cumtime percall filename:lineno(function)
   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 -指tottime除以ncall的商。 cumtime -它是在此子功能和所有子功能中花费的累积时间。递归函数甚至更准确。 percall -它是cumtime除以原始调用的商。 filename:lineno(function)-基本上提供每个函数的相应数据。
昵称: 邮箱:
Copyright © 2022 立地货 All Rights Reserved.
备案号:京ICP备14037608号-4