本文以一个通过采样求圆周率pi的脚本,介绍一些常用的对Python脚本进行性能分析的方法,针对cpu-bound的问题,找到限制执行速度的瓶颈,为下一步的代码优化做准备
# 使用time模块
import numpy as np
import time
def estimate_pi(n_estimator):
count = 0
for i in range(n_estimator):
x = np.random.rand()
y = np.random.rand()
if x**2 + y**2 <= 1:
count += 1
return count / n_estimator
start_t = time.time()
pi = estimate_pi(1000000)
end_t = time.time()
print('time cost : %f'%(end_t - start_t))
# 使用装饰器
import numpy as np
import time
def time_wrapper(fn):
def inner(*args, **kwargs):
start_t = time.time()
result = fn(*args, **kwargs)
end_t = time.time()
print('time cost : %f'%(end_t - start_t))
return result
return inner
@time_wrapper
def estimate_pi(n_estimator):
count = 0
for i in range(n_estimator):
x = np.random.rand()
y = np.random.rand()
if x**2 + y**2 <= 1:
count += 1
return count / n_estimator
pi = estimate_pi(1000000)
# 对pi值进行估计
# test.py
import numpy as np
def estimate_pi(n_estimator):
count = 0
for i in range(n_estimator):
x = np.random.rand()
y = np.random.rand()
if x**2 + y**2 <= 1:
count += 1
return count / n_estimator
if __name__ == '__main__':
pi = estimate_pi(1000000)
# IPython
%run -p test.py
得到如下结果
说明estimate_pi这个函数的调用一共用了3.07s,其中1.265s花费在numpy的rand函数的调用上,剩下1.805s是花费在其他一些类似循环中的数值计算上面
# IPython
# -l 3 表示只显示前3行的
# 也可以加上 -s 的选项对结果按照指定的选项进行排序输出
%prun -l 3 estimate_pi(1000000)
# cmd
# 也可以加上一些 -s 的选项对输出结果进行定制
python -m cProfile test.py
上面的方法是对每个函数的耗时进行分析,下面介绍一种对函数中每行代码的耗时进行分析的方法,所以建议先进行每个函数的耗时分析,然后针对性的逐行分析
# 对pi值进行估计
import numpy as np
@profile
def estimate_pi(n_estimator):
count = 0
for i in range(n_estimator):
x = np.random.rand()
y = np.random.rand()
if x**2 + y**2 <= 1:
count += 1
return count / n_estimator
if __name__ == '__main__':
pi = estimate_pi(1000000)
# cmd
kernprof -l -v test.py