0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

能快速找到代码运行最慢部分的编程神器

Linux爱好者 来源:Python七号 作者:somenzz 2021-10-13 16:40 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

天下武功,唯快不破。

编程也不例外,你的代码跑的快,你能快速找出代码慢的原因,你的码功就高。

今天分享一个超级实用的 Python 性能分析工具 pyinstrument ,可以快速找到代码运行最慢的部分,帮助提高代码的性能。支持 Python 3.7+ 且能够分析异步代码,仅需一条命令即可显示具体代码的耗时。经常写 Python 的小伙伴一定要用一下。

安装

pipinstallpyinstrument

简单的使用

在程序的开始,启动 pyinstrument 的 Profiler,结束时关闭 Profiler 并打印分析结果如下:

frompyinstrumentimportProfiler

profiler=Profiler()
profiler.start()

#这里是你要分析的代码

profiler.stop()

profiler.print()

比如这段代码 123.py,我们可以清楚的看到是列表推导式比较慢:

frompyinstrumentimportProfiler

profiler=Profiler()
profiler.start()

#这里是你要分析的代码
a=[iforiinrange(100000)]
b=(iforiinrange(100000))

profiler.stop()
profiler.print()

上述分析需要修改源代码,如果你使用命令行工具,就不需要修改源代码,只需要执行 pyinstrument xxxx.py 即可:

比如有这样一段排序的程序 c_sort.py:

importsys
importtime

importnumpyasnp

arr=np.random.randint(0,10,10)

defslow_key(el):
time.sleep(0.01)
returnel

arr=list(arr)

foriinrange(10):
arr.sort(key=slow_key)

print(arr)

这段代码里面故意放了一句 time.sleep(0.01) 来延迟性能,看看 pyinstrument 能否识别,命令行执行 pyinstrument c_sort.py:

从结果来看,程序运行了 1.313 秒,而 sleep 就运行了 1.219 秒,很明显是瓶颈,现在我们把它删除,再看看结果:

删除之后,性能最慢的就是 numpy 模块的初始化代码 __init__.py了,不过这些代码不是自己写的,而且并不是特别慢,就不需要去关心了。

分析 Flask 代码

Web 应用也可以使用这个来找出性能瓶颈,比如 flask,只需要在请求之前记录时间,在请求之后统计时间,只需要在 flask 的请求拦截器里面这样写:

fromflaskimportFlask,g,make_response,request
app=Flask(__name__)

@app.before_request
defbefore_request():
if"profile"inrequest.args:
g.profiler=Profiler()
g.profiler.start()

@app.after_request
defafter_request(response):
ifnothasattr(g,"profiler"):
returnresponse
g.profiler.stop()
output_html=g.profiler.output_html()
returnmake_response(output_html)

假如有这样一个 API:

@app.route("/dosomething")
defdo_something():
importrequests
requests.get("http://google.com")
return"Googlesayshello!"

为了测试这个 API 的瓶颈,我们可以在 url 上加一个参数 profile 就可以:http://127.0.0.1:5000/dosomething?profile,哪一行代码执行比较慢,结果清晰可见:

分析 Django 代码

分析 Django 代码也非常简单,只需要在 Django 的配置文件的 MIDDLEWARE 中添加

"pyinstrument.middleware.ProfilerMiddleware",

然后就可以在 url 上加一个参数 profile 就可以:

如果你不希望所有人都能看到,只希望管理员可以看到,settings.py 可以添加这样的代码:

defcustom_show_pyinstrument(request):
returnrequest.user.is_superuser

PYINSTRUMENT_SHOW_CALLBACK="%s.custom_show_pyinstrument"%__name__

如果不想通过 url 后面加参数的方式查看性能分析,可以在 settings.py 文件中添加:

PYINSTRUMENT_PROFILE_DIR='profiles'

这样,每次访问一次 Django 接口,就会将分析结果以 html 文件形式保存在 项目目录下的 profiles 文件夹中。

分析异步代码

简单的异步代码分析:

async_example_simple.py:

importasyncio

frompyinstrumentimportProfiler

asyncdefmain():
p=Profiler()
withp:
print("Hello...")
awaitasyncio.sleep(1)
print("...World!")
p.print()

asyncio.run(main())

复杂一些的异步代码分析:

importasyncio
importtime

importpyinstrument

defdo_nothing():
pass

defbusy_wait(duration):
end_time=time.time()+duration

whiletime.time()< end_time:
        do_nothing()

async def say(what, when, profile=False):
    ifprofile:
p=pyinstrument.Profiler()
p.start()

busy_wait(0.1)
sleep_start=time.time()
awaitasyncio.sleep(when)
print(f"sleptfor{time.time()-sleep_start:.3f}seconds")
busy_wait(0.1)

print(what)
ifprofile:
p.stop()
p.print(show_all=True)

loop=asyncio.get_event_loop()

loop.create_task(say("firsthello",2,profile=True))
loop.create_task(say("secondhello",1,profile=True))
loop.create_task(say("thirdhello",3,profile=True))

loop.run_forever()
loop.close()

工作原理

Pyinstrument 每 1ms 中断一次程序,并在该点记录整个堆栈。它使用 C 扩展名和 PyEval_SetProfile 来做到这一点,但只每 1 毫秒读取一次读数。你可能觉得报告的样本数量有点少,但别担心,它不会降低准确性。默认间隔 1ms 是记录堆栈帧的下限,但如果在单个函数调用中花费了很长时间,则会在该调用结束时进行记录。如此有效地将这些样本“打包”并在最后记录。

Pyinstrument 是一个统计分析器,并不跟踪,它不会跟踪您的程序进行的每个函数调用。相反,它每 1 毫秒记录一次调用堆栈。与其他分析器相比,统计分析器的开销比跟踪分析器低得多。

比如说,我想弄清楚为什么 Django 中的 Web 请求很慢。如果我使用 cProfile,我可能会得到这个:

151940functioncalls(147672primitivecalls)in1.696seconds

Orderedby:cumulativetime

ncallstottimepercallcumtimepercallfilename:lineno(function)
10.0000.0001.6961.696profile:0(at0x1053d6a30,file"./manage.py",line2>)
10.0010.0011.6931.693manage.py:2()
10.0000.0001.5861.586__init__.py:394(execute_from_command_line)
10.0000.0001.5861.586__init__.py:350(execute)
10.0000.0001.1421.142__init__.py:254(fetch_command)
430.0130.0001.1240.026__init__.py:1()
3880.0080.0001.0620.003re.py:226(_compile)
1580.0050.0001.0480.007sre_compile.py:496(compile)
10.0010.0011.0421.042__init__.py:78(get_commands)
1530.0010.0001.0360.007re.py:188(compile)
106/1020.0010.0001.0300.010__init__.py:52(__getattr__)
10.0000.0001.0291.029__init__.py:31(_setup)
10.0000.0001.0211.021__init__.py:57(_configure_logging)
20.0020.0011.0110.505log.py:1()

看完是不是还是一脸懵逼,通常很难理解您自己的代码如何与这些跟踪相关联。Pyinstrument 记录整个堆栈,因此跟踪昂贵的调用要容易得多。它还默认隐藏库框架,让您专注于影响性能的应用程序/模块:

_.___/_______/_Recorded:1435Samples:131
/_//_////_///_/////_'///Duration:3.131CPUtime:0.195
/_/v3.0.0b3

Program:examples/django_example/manage.pyrunserver--nothreading--noreload

3.131manage.py:2
└─3.118execute_from_command_linedjango/core/management/__init__.py:378
[473frameshidden]django,socketserver,selectors,wsgi...
2.836selectselectors.py:365
0.126_get_responsedjango/core/handlers/base.py:96
└─0.126hello_worlddjango_example/views.py:4

最后的话

本文分享了 pyinstrument 的用法,有了这个性能分析神器,以后优化代码可以节省很多时间了,这样的效率神器很值得分享,毕竟人生苦短,能多点时间干点有意思的不香么?

责任编辑:haq


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编程
    +关注

    关注

    90

    文章

    3707

    浏览量

    96765
  • 代码
    +关注

    关注

    30

    文章

    4941

    浏览量

    73148

原文标题:效率神器:快速定位运行最慢的代码

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    MCU代码需要搬到RAM中才能运行吗?不这样做会有什么不妥嘛?

    部分单片机的代码直接在nor flash中运行,少部分需要加载到ram中。 nor flash可以直接寻址一个字节,可以找到一个指令的具体
    发表于 12-04 07:39

    在极海APM32系列MCU中如何把代码重定位到SDRAM运行

    在有些情况下,我们想要把代码放到SDRAM运行。下面介绍在APM32的MCU中,如何把代码重定位到SDRAM运行。对于不同APM32系列的MCU,方法都是一样的。
    的头像 发表于 11-04 09:14 4831次阅读
    在极海APM32系列MCU中如何把<b class='flag-5'>代码</b>重定位到SDRAM<b class='flag-5'>运行</b>

    物联网平台应用环境监控:低代码编程简化开发,组态应用

    复杂开发转化为“拖拽组件、关联设备”的简单操作,让企业无需编程快速搭建、灵活调整监控系统,适配工业、园区、农业等多场景环境监控需求。 一、低代码
    的头像 发表于 08-29 15:33 606次阅读

    TLE9893是否支持在FLASH1上运行代码来擦除和编程FLASH1?

    芯片TLE9893是否支持在FLASH1上运行代码来擦除和编程FLASH1。在NVM-PROG_UCODE中,代码在FLASH1上运行,并将
    发表于 08-13 08:14

    代码开发云平台是什么?零编程零成本搭建

    代码物联网云平台是种融合了低代码开发能力与物联网(IoT)技术的云端服务平台,其核心目标是大幅降低物联网应用的开发门槛和成本,让用户无需专业编程经验,也
    的头像 发表于 07-31 15:25 585次阅读

    STM32IDE如何设定代码到ITCM中运行

    近期使用STM32MUX生成STM32IDE的代码(MCU是STM32H743),目前希望可以将部分代码定位到ITCM中运行,加快处理速度,关于代码
    发表于 06-24 06:45

    零基础学习LuatOS编程快速上手开发实战教程!

    到实践的跨越。 学习LuatOS的主要方法之一是“运行各个功能模块的demo代码”,本期特别分享——LuatOS编程起步相关内容。   注意:本文档的读者,默认都已经了解初步的Lua语法。   如果不懂Lua语法的话,可以参考下
    的头像 发表于 06-13 17:27 450次阅读
    零基础学习LuatOS<b class='flag-5'>编程</b>:<b class='flag-5'>快速</b>上手开发实战教程!

    同样的代码在官方开发板上运行正常,在自己板子上就跑不起来,怎么办?

    UART交互,CLI代码所在目录为:SDK安装目录examplesperipheralcli。如果这2个程序运行正常,说明你的焊接问题
    的头像 发表于 05-12 15:26 583次阅读
    同样的<b class='flag-5'>代码</b>在官方开发板上<b class='flag-5'>运行</b>正常,在自己板子上就跑不起来,怎么办?

    在i.MX RT 1176上正常运行代码时与使用IAR调试代码时存在一些奇怪的差异,为什么?

    我在 i.MX RT 1176 上正常运行代码时的行为与使用 IAR 调试代码时的行为之间存在一些奇怪的差异,并注意到这是由于堆栈指针的初始化方式造成的。 我的重置向量表将其指向 DTC 的顶部
    发表于 03-17 07:26

    STM32使用ISp烧录HEX文件运行代码重新编译之后的产生的新hex文件选择全片擦除就没办法正常运行,为什么?

    ISP选择擦除重要部分在下载,才是正常的正确的代码现象是灯可以闪烁,连接上串口。新编译的HEX文件如果全片擦除,则没有任何现象。只有选择老的(正确的)HEX文件ISP下载一次,新编译的HEX文件再ISP烧录一遍才能够
    发表于 03-10 07:42

    DLPLCRC410EVM参考appsfpga代码时,没有找到obufds这个模块,怎么回事?

    在参考appsfpga 代码时,没有找到obufds这个模块,请问这个是TI提供吗,还是和xlinx有关,这一块有点不太清楚,希望有人帮忙解答一下,谢谢
    发表于 02-26 06:46

    DLPC230的应用程序烧录文件在哪里找到

    , 请问哪里有这个C代码的例程吗, 不会完全要按照手册自己写配置代码吧。。。 另外, 这个DLPC230的应用程序烧录文件在哪里找到
    发表于 02-24 07:28

    HarmonyOS 应用开发赋套件:鸿蒙原生应用开发的 “神助攻”

    的课程、文档、样例代码等资源,在开发者旅程各阶段提供全方位的支持。开发者可以通过鸿蒙开发者官网一站式获取HarmonyOS赋套件。 感知阶段:快速了解鸿蒙开发理念与最新动态   感知阶段主要面向
    发表于 02-17 16:37

    代码平台:快速搭建与优化MES系统,提升生产效率

    一、低代码平台概述 低代码平台是一种可视化的软件高效开发平台,它通过抽象和最小化手工编码的方式,为开发和部署定制化应用提速。低代码平台的主要特点是让使用者通过可视化的方式,以更少的编码、更快速
    的头像 发表于 01-23 09:37 587次阅读
    低<b class='flag-5'>代码</b>平台:<b class='flag-5'>快速</b>搭建与优化MES系统,提升生产效率

    电脑相片云存储位置,如何快速找到电脑相片云存储位置

    在数字化时代,传统的电脑已经无法满足我们对高效、便捷计算的需求。云电脑以其强大的功能和灵活的使用方式,成为了新时代的宠儿。今天就为大家介绍如何快速找到电脑相片云存储位置。    在现代办公和生活中
    的头像 发表于 01-16 10:44 4198次阅读
    电脑相片云存储位置,如何<b class='flag-5'>快速</b><b class='flag-5'>找到</b>电脑相片云存储位置