在这里插入图片描述

对于我这种学艺不精的渣渣来说,写出运行耗时较多的代码是很经常出现的(尴尬,嘿嘿嘿!)。前不久就在自己之前使用的代码上栽了跟头,师兄的代码只用了一到两分钟,而我的用了十多分钟,虽说他用的是perl,但我在想python不可能就是真的这么慢吧。最后想着还是看下是不是自己的代码确实很烂,我就尝试寻找能计算每行代码运行时间的包,最终还真的找到了,就是要介绍的line_profiler啦。其它工具可能也有,例如Heartrate等等,但感觉用起来没有line_profiler方便,我也就没用啦。最终也发现确实是自己的代码写的菜!!!经过一番修改之后速度快了好多倍。。。

当然这种模块呢,我们一般就是在测试时用一下,所以能够到达基本使用的地步我觉得就足够啦,所以本文就仅仅教大家怎么去简单的使用就OK啦!还有就是profile在这里可以理解成性能剖析的意思哦!


安装line_profiler

安装直接使用 pip install line_profiler 命令即可,但是我在我的win10电脑上使用这个命令是会报错的,报错非常长的一串,部分截图如下:
在这里插入图片描述
开始报错的地方写着 Building wheel for line-profiler (PEP 517) … error,这个错我也在网上搜索了很久,最终还是没有解决,按照某个博主的教学安装Cpython也不行。最后在某篇文章还是回答中看到了可以使用anaconda的conda install试试,最后我也只有妥协重新装上anaconda再配置好python环境等等环境变量,最后再使用conda install line_profiler就没问题啦。

这是我个人的粗劣的解决方式,读者若有好方法也可以提出来呀!

但是也不一定大家都会碰上这个问题哦,我在linux服务器上就可以直接使用pip安装的哦。没有问题就可以不用管啦!

使用方式1(使用profile装饰器)

要注意line_profiler只能计算函数中代码的运行时间哦,所以要计算时间的话就先把代码转换到函数中吧。使用line_profiler大致有两种方式,即:

  • 在命令行调用包作者的脚本kernprof来运行你的py文件
  • 在脚本中写上使用line_profiler的方式。

这两种方法都可以,看哪个合适就用哪个吧!

由于连接网络可能会多花些时间,看起来效果会更好。就用简单的爬虫来举例啦!简单的爬虫的知识大家可以参考我之前写的文章哦!在这里

话不多说,先看方式1:

# 脚本名为test.py
import requests

headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'}
# 加的一个请求头,这样就可以简单的伪装成浏览器啦

   
# 使用line_profiler的第一种方式需要加上这个profile装饰器,在编辑器中由于有拼写检查,
# 这个地方可能会报错,但是不用管啦,反正我们是在命令行运行脚本的,kernprof会自动帮我们处理的。
@profile 
def get_url_txt(url_list):
    f = open('text.txt','w',encoding='utf-8')
    for url in url_list:
        text = requests.get(url, headers=headers).text
        f.write(text)
    return 'finished'

url_list = ['http://www.baidu.com', 'http://www.taobao.com',\
            'https://blog.csdn.net/keepaware/article/details/111655393']
# 传入一个要爬取的网址列表

result = get_url_txt(url_list)
# 调用函数
print(result)
# 查看返回值

这段代码,我在我的windows命令行将当前目录切换到脚本存放位置后,使用 kernprof -l -v test.py即可开始运行代码(-l 代表逐行分析,-v代表将结果打印出来),运行的结果如下:

# 复制过来的是文本,我直接在上面注释一下哈
finished
Wrote profile results to rg.py.lprof
Timer unit: 1e-07 s     
# 这应该是计时的单位
Total time: 1.81267 s
# 总共花去的时间
File: test.py
Function: get_url_txt at line 7
# 计时的函数

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     7                                           @profile
     8                                           def get_url_txt(url_list):
     9         1      44804.0  44804.0      0.2      f = open('text.txt','w',encoding='utf-8')
    10         4         75.0     18.8      0.0      for url in url_list:
    11         3   18061366.0 6020455.3     99.6          text = requests.get(url, headers=headers).text
    12         3      20404.0   6801.3      0.1          f.write(text)
    13         1          3.0      3.0      0.0      return 'finished'

# 上面这一段就是运行代码的时间结果啦,hits即某行代码运行了几次,
# time应该就是使用的时间,这里需要乘以上面的时间单位才是真正用掉的时间,
# 所以可以看到最久时间的11行都只花了18061366 * 1e-07 s哦。
# 后面per hit就是每次运行某行代码所花的时间,% Time 就是占据整个
# 代码运行时间的百分比呗。还是很好理解的,是吧!

使用方式2(直接在脚本中调用LineProfiler)

import requests
import line_profiler as lp

headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'}

# 这种方式就不用加profile装饰器啦
def get_url_txt(url_list):
    f = open('text.txt','w',encoding='utf-8')
    for url in url_list:
        text = requests.get(url, headers=headers).text
        f.write(text)
    return 'finished'
    
url_list = ['http://www.baidu.com', 'http://www.taobao.com',
            'https://blog.csdn.net/keepaware/article/details/111655393']

profile = lp.LineProfiler(get_url_txt)
# 自己制作一个profile工具,并且传入要分析的代码
profile.enable()
# 起始分析
get_url_txt(url_list)
# 调用函数,这里还是正常传入参数的哦
profile.disable()
# 停止分析,这里就相当于只分析get_url_txt这个函数
profile.print_stats()
# 打印结果

运行的结果同上,不展示咯!

使用方式3(直接在脚本中调用LineProfiler)

import requests
from line_profiler import LineProfiler
# 只需要导入LineProfiler即可

headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'}


def get_url_txt(url_list):
    f = open('text.txt','w',encoding='utf-8')
    for url in url_list:
        text = requests.get(url, headers=headers).text
        f.write(text)
    return 'finished'

url_list = ['http://www.baidu.com', 'http://www.taobao.com',
            'https://blog.csdn.net/keepaware/article/details/111655393']

lp = LineProfiler()
# 使用LineProfiler来分析
profile = lp(get_url_txt)
# 这里还可以使用profile.add_function()来添加你想要额外计算的函数哦,就不再介绍了,我也还没用过。
# 同样制作profile
profile(url_list)
# 但这里传入给profile的是参数,替代了上面向函数传入的方式
lp.print_stats()
# 打印结果

运行结果也同上哦,这里就不再展示了。

产生的结果文件

细心的你可能会发现运行这个工具会产生一个文件,后缀是.py.lprof,我这里全名也就是test.py.lprof。这个文件也是有记录你代码运行时间的结果的哦,所以你也可以查看这个文件来回顾之前的时间记录。

使用方式为:

python -m line_profiler test.py.lprof
# 这样就能看到和刚刚你看到的结果一样的结果啦。
# 这里python -m代表的是将后面模块当做脚本来运行,line_profiler是我们安装的模块嘛!这样还不需要
# 我们去寻找这个脚模块的绝对路径的哈,所以还是比较方便的。
# -m具体我也还没搞懂,后面会再了解一下

个人觉得这个工具还是挺好用的,用来查看某些代码花去的时间,来适当修改自己的代码。网上教程也挺多的,但是好像有点乱,所以就整理了一下,希望能帮上有需要的人哦!

刚刚看到其实除了line_profiler外还有一个memory_profiler,是用来计算每行代码消耗内存量的工具,使用方式好像和line_profiler差不多,大家有兴趣也可以了解一下哦,不过实际上现在电脑的内存都还是较大,一般情况下还是不太需要用来测试内存使用量的。

参考:line_profiler 逐行分析
参考:How do I use line_profiler (from Robert Kern)?
参考:https://github.com/rkern/line_profiler

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐