当前位置: 首页 > 科技观察

让Python程序快30%的小窍门

时间:2023-03-19 16:29:50 科技观察

Python的性能一直是被人们诟病的问题之一,抱怨执行速度慢,无法使用。虽然在性能方面语言差异确实存在明显差异,但我认为对于一个非常流行的语言来说,运行速度不会成为阻碍人们使用它的因素。如果是,可能是写的程序有问题,需要优化。本文将介绍如何调试Python应用程序的性能以及如何对其进行优化。Python性能调试要进行Python性能调试,前提是找出程序中的性能瓶颈。找出程序中影响程序性能的代码。有经验的开发人员一般可以很容易地找到程序的瓶颈,但普通的编码人员很难找到系统有问题的代码。为了快速有效地找到程序的性能瓶颈,需要进行性能调试。下面我们以一个实际的例子来介绍一下。下面的程序是计算e的x(1..n)次幂。代码如下:#performance.pyfromdecimalimport*defexp(x):getcontext().prec+=2i,lasts,s,fact,num=0,0,1,1,1whiles!=lasts:lasts=si+=1fact*=inum*=xs+=num/factgetcontext().prec-=2return+sprint(exp(Decimal(150)))print(exp(Decimal(400)))print(exp(Decimal(3000)))最简单的debuggingThesimplestandmostpracticalwaytodebugperformancedebuggingistousetheLinuxtimecommand,timecancalculatetheexecutiontimeoftheprogram:timepython3performance.py1.393709580666379697318341937E+655.221469689764143950588763007E+1737.646200989054704889310727660E+1302real0m15.185suser0m15.100ssys0m0.004s计算前两个数的(150,400)很快,而第三个大一点时会很慢,总要15秒多才算完了,有点卡(慢)。时间虽然方便有用,但不能给我们详细的代码性能细节。详细的性能分析cProfile性能分析的另一种常用方法是使用cProfile,它可以提供大量的性能信息对行进行排序。如上图所示,使用cProfile可以给出很多内部具体的信息,通过这些信息我们可以知道主要的耗时是由exp函数引起的。知道了程序的性能瓶颈,下面来讲解一下Python性能分析和优化。优化具体功能知道了性能瓶颈在哪里(例子中的exp函数),我们使用一个简单的装饰器跳过其他代码,专门分析针对性能瓶颈设计的功能,以便进一步分析具体问题。然后使用装饰器进行测试,具体代码如下:deftimeit_wrapper(func):@wraps(func)defwrapper(*args,**kwargs):start=time.perf_counter()#Alternatively,youcanusetime.process_time()func_return_val=func(*args,**kwargs)end=time.perf_counter()print('{0:<10}.{1:<8}:{2:<8}'.format(func.__module__,func.__name__,end-start))returnfunc_return_valreturnwrapper我们使用这个装饰器来测试exp:@timeit_wrapperdefexp(x):...print('{0:<10}{1:<8}{2:^8}'.format('module','function','time'))exp(Decimal(150))exp(Decimal(400))exp(Decimal(3000))result:modulefunctiontime__main__.exp:0.00920036411844194__main__.exp:0.09822067408822477__main__.exp:15.228459489code,我们使用time包提供了time.perf_counter函数,同时也提供了另外一个函数time.process_time。两者的区别是perf_counter返回的绝对时间,包括Python程序进程未运行时的时间,可能受电脑负载影响。而process_time只返回用户时间(不包括系统时间),也就是程序处理时间而已。性能优化说到底就是Python程序的性能优化。为了让Python程序运行得更快,我们提供一些性能优化思路和策略供参考。通过这些策略,我们可以将应用程序的运行速度提高一半。在最高的情况下,我们可以让你的应用程序快30%。使用内置数据类型显然,内置数据类型非常快,尤其是与自定义类型(例如树或链表)相比。由于内置程序是用C语言实现的,其性能优势是Python代码无法比拟的。使用lru_cache缓存/内存在很多情况下非常有效,可以大大提高性能,尤其是在数值计算和涉及大量重复调用(递归)时。考虑一个例子:上面的函数使用time.sleep(2)来模拟一个耗时代码。第一次使用参数1调用时,它将等待2秒,然后返回结果。再次调用时,由于结果已经缓存,函数的执行将被跳过,直接返回。用3调用时,由于参数不同,需要2秒,整体耗时应该是4秒。我们用时间验证:real0m4.061suser0m0.040ssys0m0.015s,与我们的假设一致。局部变量的使用是看在变量作用域内查找的速度,函数中的局部变量速度快。接下来是类级属性(如self.name),最慢的是全局变量,如time.time(最慢)。所以我们可以通过避免不必要的全局变量来提高性能。这对于函数来说似乎有点出乎意料,因为函数涉及的内存占用都在堆栈上,并且函数返回也有开销。但是使用函数,可以避免使用全局变量,这样可以提高性能。因此,可以通过将整个代码包装在main函数中并仅调用一次来加快代码速度。避免使用属性另一个会影响程序性能的操作是访问对象属性的点运算符。点运算符使用__getattribute__触发字典查找,这会在代码中产生额外的开销。我们可以通过使用函数而不是类方法来避免点操作,例如下面的示例:findall(regex,line)当在循环中使用格式字符(%s)或.format()时,字符串操作会变得非常慢F弦。为了性能优化,我们应该使用f-string。这是Python3.6中引入的非常可读、简洁和最快的方法。例如:s+''+t''.join((s,t))'%s%s'%(s,t)'{}{}'.format(s,t)Template('$s$t').substitute(s=s,t=t)#Slowcodef'{s}{t}'#Fastcode总结性能调试和优化是非常重要的编码技术之一。在本文中,我们提供了调试和优化Python应用程序性能的技巧和策略,希望对大家有所帮助。