python profiler_Python 性能调试工具Line-profiler极简使用笔记

虽然Python屡屡被人诟病速度问题,但是该用的还得用,速度问题只能靠代码优化来解决了。Line-Profiler是一个代码优化工具,利用line—profiler我们可以得到我们每一行代码的运行总时间以及单次平均运行时间,以便我们对耗时最长的地方进行优化。

1、极简模式

下面我们使用line-profiler查看一个简单实例各行代码时间都花在哪。

import random

def do_stuff():

numbers = []

for i in range(1000):

numbers.append(random.randint(0,1000))

s = sum(numbers)

l = [numbers[i]/43 for i in range(len(numbers))]

m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

return None

if __name__ == '__main__':

from line_profiler import LineProfiler

lp = LineProfiler()

lp_wrapper = lp(do_stuff)

lp_wrapper()

lp.print_stats()

下面我们再命令行运行一下看看时间都去哪了:

$ root@cpu-k8ss-0 # python loader_test.py

Timer unit: 1e-06 s

Total time: 0.0075 s

File: loader_test.py

Function: do_stuff at line 88

Line # Hits Time Per Hit % Time Line Contents

==============================================================

88 def do_stuff():

89 1 1.0 1.0 0.0 numbers = []

90 1001 697.0 0.7 9.3 for i in range(1000):

91 1000 6093.0 6.1 81.2 numbers.append(random.randint(0,1000))

92 1 10.0 10.0 0.1 s = sum(numbers)

93 1 240.0 240.0 3.2 l = [numbers[i]/43 for i in range(len(numbers))]

94 1 458.0 458.0 6.1 m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

95 1 1.0 1.0 0.0 return None

上面输出中,可以看到我们测试的函数为do_stuff, 起始于位于脚本的第88行。运行程序共花费时间0.0075 s。

紧接着的各列含义如下:

Line #, 对应脚本中的代码行数;

Hits,对应行共计运行次数;

Time,对应行运行总时间;

Per Hit,对应行平均每次运行时间;

% Time, 对应行运行时间占程序运行总时间的比例;

Line Contents,对应的每一行的代码内容。

从上面可以看到我们的时间主要花在了第一个生成数据的for循环中,共计占了90.5%,我们可以使用列表推导式来对其进行优化。

$ root@cpu-k8ss-0 # python loader_test.py

Timer unit: 1e-06 s

Total time: 0.00503 s

File: loader_test.py

Function: do_stuff at line 88

Line # Hits Time Per Hit % Time Line Contents

==============================================================

88 def do_stuff():

89 # numbers = []

90 # for i in range(1000):

91 # numbers.append(random.randint(0,1000))

92 1 4434.0 4434.0 88.2 numbers = [random.randint(1,100) for i in range(1000)]

93 1 8.0 8.0 0.2 s = sum(numbers)

94 1 194.0 194.0 3.9 l = [numbers[i]/43 for i in range(len(numbers))]

95 1 393.0 393.0 7.8 m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

96 1 1.0 1.0 0.0 return None

可以看到使用列表推导式后,我们的总时间减少了,生成数据这一步占程序总运行时间比例也降低了。

给函数传入参数

下面我们将numbers数据生成过程放到外面,以参数形式传入到函数中:

def do_stuff(numbers):

# numbers = []

# for i in range(1000):

# numbers.append(random.randint(0,1000))

#numbers = [random.randint(1,100) for i in range(1000)]

s = sum(numbers)

l = [numbers[i]/43 for i in range(len(numbers))]

m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

return None

if __name__ == '__main__':

from line_profiler import LineProfiler

lp = LineProfiler()

lp_wrapper = lp(do_stuff)

# 生成参数并传入

numbers = [random.randint(1,100) for i in range(100000)]

lp_wrapper(numbers)

lp.print_stats()

命令行运行:

$ root@cpu-k8ss-0 # python loader_test.py

Timer unit: 1e-06 s

Total time: 0.084887 s

File: loader_test.py

Function: do_stuff at line 88

Line # Hits Time Per Hit % Time Line Contents

==============================================================

88 def do_stuff(numbers):

89 # numbers = []

90 # for i in range(1000):

91 # numbers.append(random.randint(0,1000))

92 #numbers = [random.randint(1,100) for i in range(1000)]

93 1 788.0 788.0 0.9 s = sum(numbers)

94 1 26504.0 26504.0 31.2 l = [numbers[i]/43 for i in range(len(numbers))]

95 1 57593.0 57593.0 67.8 m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

96 1 2.0 2.0 0.0 return None

可以看到,现在程序运行的时间主要花在计算除数和连接字符串了。

显示内层调用函数的运行时间

在上面的例子中,我们将所有代码放在了一个函数中,只查看这个函数的代码的运行时间。line-profiler支持查看调用的函数内部运行时间。

def generate_numbers(n):

numbers = [random.randint(1,100) for i in range(1000)]

return numbers

def do_stuff(n):

numbers = generate_numbers(n)

s = sum(numbers)

l = [numbers[i]/43 for i in range(len(numbers))]

m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

return None

if __name__ == '__main__':

from line_profiler import LineProfiler

lp = LineProfiler()

lp_wrapper = lp(do_stuff)

# 加入并显示调用函数各行代码用时

lp.add_function(generate_numbers)

# 生成参数并传入

n = 100000

lp_wrapper(n)

lp.print_stats()

命令行运行:

$ root@cpu-k8ss-0 # python loader_test.py

Timer unit: 1e-06 s

Total time: 0.005112 s

File: loader_test.py

Function: generate_numbers at line 87

Line # Hits Time Per Hit % Time Line Contents

==============================================================

87 def generate_numbers(n):

88 1 5111.0 5111.0 100.0 numbers = [random.randint(1,100) for i in range(1000)]

89 1 1.0 1.0 0.0 return numbers

Total time: 0.005709 s

File: loader_test.py

Function: do_stuff at line 92

Line # Hits Time Per Hit % Time Line Contents

==============================================================

92 def do_stuff(n):

93 1 5125.0 5125.0 89.8 numbers = generate_numbers(n)

94 1 8.0 8.0 0.1 s = sum(numbers)

95 1 189.0 189.0 3.3 l = [numbers[i]/43 for i in range(len(numbers))]

96 1 387.0 387.0 6.8 m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

97 1 0.0 0.0 0.0 return None

在上面我们可以看到两个函数各行代码的运行时间,非常方便。

当然,line-profile还可以通过装饰器@profiler方式统计我们想要优化的函数。然后在命令行中通过命令$ kernprof -l script_to_profile.py来进行运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值