一、什么是Python Wall Time和CPU Time
Python中,“Wall Time”和“CPU Time”是衡量程序执行时间和资源消耗的两个指标。Wall Time反映的是实际流逝的时间,即程序开始执行到执行完成所经过的时间;而CPU Time则反映的是程序单独占用CPU的时间,不包括等待输入输出和其他外部因素所耗费的时间。
下面是一个简单的代码示例来说明它们的区别:
import time # 测试程序:计算0~999999的和 start_time = time.time() s = 0 for i in range(1000000): s += i end_time = time.time() print("Wall Time:", end_time - start_time) start_cpu = time.process_time() s = 0 for i in range(1000000): s += i end_cpu = time.process_time() print("CPU Time:", end_cpu - start_cpu)
当我们运行上面这段程序时,输出结果可能类似于:
Wall Time: 0.123456 CPU Time: 0.038461
可以看到,Wall Time和CPU Time的数值差别很大,这是因为Python程序在执行过程中经常会因为等待输入输出、等待其他任务完成等原因而暂停运行,导致Wall Time比CPU Time长。
二、如何计算多个函数的Wall Time和CPU Time
当我们需要比较不同的函数在程序中的执行时间和资源消耗时,我们可以使用Python内置的装饰器来计算它们的Wall Time和CPU Time。
首先,我们定义一个装饰器函数来计算函数的Wall Time:
import time def calculate_wall_time(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(func.__name__, "Wall Time:", end_time - start_time) return result return wrapper
定义好装饰器函数后,我们在需要计算Wall Time的函数前加上@calculate_wall_time修饰符即可:
@calculate_wall_time def func_1(): ...
类似地,我们可以定义另一个装饰器函数来计算函数的CPU Time:
import time def calculate_cpu_time(func): def wrapper(*args, **kwargs): start_cpu = time.process_time() result = func(*args, **kwargs) end_cpu = time.process_time() print(func.__name__, "CPU Time:", end_cpu - start_cpu) return result return wrapper
使用方法同上:
@calculate_cpu_time def func_2(): ...
通过使用装饰器函数,我们可以方便地计算多个函数的Wall Time和CPU Time,并进行比较。
三、如何使用profiler分析程序的性能问题
在比较重要的程序中,我们需要进行更深入的分析才能确定性能瓶颈出现在哪里。Python的内置模块profiler可以帮助我们分析程序的性能问题。
例如,我们定义一个复杂的函数来计算斐波那契数列的第n项:
import time def fib(n): if n <= 1: return n else: return fib(n-1) + fib(n-2)
如果我们需要计算fib(35)时的Wall Time和CPU Time,我们可以使用之前的装饰器函数来计算:
@calculate_wall_time def test_wall_time(): fib(35) @calculate_cpu_time def test_cpu_time(): fib(35) test_wall_time() test_cpu_time()
运行结果可能类似于:
test_wall_time Wall Time: 3.524221181869507 test_cpu_time CPU Time: 3.51171875
可以看到,fib(35)的Wall Time和CPU Time都比较长。使用Python内置模块cProfile可以查看这个函数每一行的运行情况和耗费的时间:
import cProfile cProfile.run('fib(35)')
运行结果可能类似于:
结果输出太长,省略...
在输出结果中,每一行都显示了这个函数在运行中的执行时间和调用次数,我们可以从中找出哪些是时间最长的部分,从而确定可能的性能瓶颈和优化方向。
四、如何优化程序的性能问题
当我们确定了程序的性能瓶颈后,就可以考虑优化程序来提高执行效率。
一些常见的优化方法有:
- 使用局部变量和常量代替全局变量和动态类型
- 使用Python内置函数和模块代替自定义函数和算法
- 使用生成器和迭代器代替列表解析和循环结构
- 使用线程和进程来利用多核CPU
例如,我们可以修改之前的斐波那契数列函数fib(n)来使用局部变量和迭代器进行优化:
def fib(n): a, b = 0, 1 for i in range(n): a, b = b, a + b return a
使用优化后的函数来计算fib(1000000)的Wall Time和CPU Time:
@calculate_wall_time def test_wall_time(): fib(1000000) @calculate_cpu_time def test_cpu_time(): fib(1000000) test_wall_time() test_cpu_time()
运行结果可能类似于:
test_wall_time Wall Time: 0.28377318382263184 test_cpu_time CPU Time: 0.28125
可以看到,使用优化后的函数计算fib(1000000)的Wall Time和CPU Time都大幅度优化了。
总结
在Python中,我们可以使用Wall Time和CPU Time来衡量程序执行时间和资源消耗,并使用内置模块profiler来分析程序的性能问题,并使用局部变量、内置函数、迭代器等技巧来优化程序的性能。