我的代码的哪些部分运行时间最长,占用的内存最多?我怎样才能找到需要改进的地方?》在开发过程中,我敢肯定我们大多数人都会想知道,在本文中总结了一些监控Python代码的时间和内存使用情况的方法。本文将介绍4种方法,前3种方法提供时间信息,第四种方法可以获取内存占用timemodule%%timemagiccommandline_profilermemory_profilertimemodule这是最简单最直接(但需要手动开发)的方法来计算代码运行所需的时间,他的逻辑也很简单:记录时间代码运行前后,计算时间差。这可以实际如下:importtimestart_time=time.time()result=5+2end_time=time.time()print('Timetaken={}sec'.format(end_time-start_time))下面的例子显示了for循环和列表推导式在时间上的差异:importtime#forloopvs.listcomplist_comp_start_time=time.time()result=[iforiinrange(0,1000000)]list_comp_end_time=time.time()print('列表comp={}sec'.format(list_comp_end_time-list_comp_start_time))result=[]for_loop_start_time=time.time()foriinrange(0,1000000):result.append(i)for_loop_end_time=time。time()print('for-loop花费的时间={}sec'.format(for_loop_end_time-for_loop_start_time))list_comp_time=list_comp_end_time-list_comp_start_timefor_loop_time=for_loop_end_time-for_loop_start_timeprint('Difference={}%'.format((for_loop_time-list_comp_time)/list_comp_time*100))我们都知道会慢一些Listcomp=0.05843973159790039secTimetakenfor-loop=0.06774497032165527secDifference=15.922795107582594%%%timeMagiccommandMagiccommand是IPython内核内置的便捷命令,可以轻松执行特定任务,一般用于jupyternotebook。在cell开头加上%%time,当cell执行完成后,会输出cell执行所花费的时间。%%timedefconvert_cms(cm,unit='m'):'''将cm转换为m或英尺的函数'''ifunit=='m':returncm/100returncm/30.48convert_cms(1000)结果如下:CPUtimes:user24μs,sys:1μs,total:25μsWalltime:28.1μsOut[8]:10.0这里的CPUtimes是CPU实际处理代码的时间,Walltime是真实事件。time,方法进入和方法退出之间的时间。line_profiler的前两个方法仅提供执行该方法所需的总时间。通过时间分析器我们可以得到函数中每段代码的运行时间。这里我们需要用到line_profiler包。使用pip安装line_profiler。importline_profilerdefconvert_cms(cm,unit='m'):'''将cm转换为m或英尺的函数'''ifunit=='m':returncm/100returncm/30.48#Loadtheprofiler%load_extline_profiler#使用profiler的魔法调用方法%lprun-fconvert_cmsconvert_cms(1000,'f')输出结果如下:Timerunit:1e-06sTotaltime:4e-06sFile:/var/folders/y_/ff7_m0c146ddrr_mctd4vpkh0000gn/T/ipykernel_22452/382784489.py函数:convert_cmsatline1Line#HitsTimePerHit%时间线内容================================================================1defconvert_cms(cm,unit='m'):2'''3将cm转换为m或英尺的函数4'''512.02.050.0ifunit=='m':6returncm/100712.02.050.0returncm/30.48可以看到line_profiler提供了每行代码花费时间的详细信息LineContents:运行的代码Hits:该行被执行的次数Time:总耗时(即Numberofhitsxperhit的hitsnumber)PerHit:执行一次耗时,也就是说Time=HitsXPerHit%Time:占总时间的比例可以看出每行代码都详细分析了时间,这对于我们的分析时间是很有帮助的。memory_profiler与line_profiler类似,memory_profiler提供代码的逐行内存使用情况。要安装它,请使用pipinstallmemory_profiler。这里我们监控convert_cms_f函数的内存使用情况fromconversionsimportconvert_cms_fimportmemory_profiler%load_extmemory_profiler%mprun-fconvert_cms_fconvert_cms_f(1000,'f')convert_cms_f函数定义在一个单独的文件中,然后导入。结果如下:Line#MemusageIncrementOccurrencesLineContents================================================================163.7MiB63.7MiB1defconvert_cms_f(cm,unit='m'):2'''3将cm转换为m或英尺的函数4'''563.7MiB0.0MiB1ifunit=='m':6returncm/100763.7MiB0.0MiB1returncm/30.48memory_profiler提供对内存使用情况的详细了解每行代码。这里1MiB(MebiByte)几乎等于1MB。1MiB=1.0485761MB但是memory_profiler也有一些缺点:它查询OS内存,所以结果可能与python解释器略有不同,如果你在一个会话中多次运行%mprun,你可能会注意到delta列报告所有代码行为0.0MiB。这是由于魔术命令的限制。memory_profiler虽然存在一些问题,但是可以让我们清晰的了解内存的使用情况,是一个非常有用的开发工具。小结虽然Python并不是一门以执行效率着称的语言,但是在一些特殊情况下这些命令对我们还是很有帮助的。
