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

1个技巧让你的Python代码运行效率提高17倍

时间:2023-03-14 20:39:11 科技观察

Mandelbrot集是一个有趣的数学现象,涉及位运算、递归和虚数。由于它是一个复杂且计算多样的函数,因此是一个很好的研究如何提高代码运行效率的案例。通过对函数mandelbrot_set的运行进行计时,我们发现这个函数平均需要8秒才能完成。importnumpyasnpdefmandelbrot_set(width,height,zoom=1,x_off=0,y_off=0,niter=256):w,h=width,heightpixels=np.arange(w*h,dtype=np.uint16).reshape(h,w)forxinrange(w):foryinrange(h):zx=1.5*(x+x_off-3*w/4)/(0.5*zoom*w)zy=1.0*(y+y_off-h/2)/(0.5*zoom*h)z=complex(zx,zy)c=complex(0,0)foriinrange(niter):ifabs(c)>4:breakc=c**2+zcolor=(i<<21)+(i<<10)+i*8pixels[y,x]=color在代码中加载Cython,效率提高25%这里,我们做一个简单的改动:我们在单独的单元中加载Cython,这是一个专门用于C和Python之间的桥梁。然后,在该单元格的顶部,键入%%cython-a以触发JupyterNotebook的换行符,通过Cython运行代码,Cython会在后台自动将Python代码转换为C。我们的函数mandelbrot_set可以在Python中调用,但可以与C结构一起使用。再次运行我们更新的代码,我们看到了将近两秒的下降。几乎什么都不做,可以提高25%的运行效率!在函数中声明变量类型,运行效率提高了17倍。但是,我们有更好的方法。当Cython试图将Python进程转换为C结构时,它的运行速度受到限制。为了帮助Cython运行得更快,我们可以做的一件事是声明函数中使用的所有变量的变量类型,这可以更好地优化我们的代码。请注意每个参数的数据类型是如何指定的(在本例中,所有数据类型都是int)。如果变量是独立创建的,可以使用cdef关键字,后跟数据类型和采用该类型的变量。从直接声明的变量到iinininininscope(n)的一切都可以尽可能地帮助Cython。使用指定的数据类型重新运行更新后的函数,我们看到运行时间大大减少,比原来快17倍!在10秒内,只修改了一种数据类型,我们的代码效率提高了17倍。虽然减少的时间只有几秒钟,但如果将此方法应用到更长的代码脚本中,节省的计算量将达数小时。它是如何工作的Cython是一个可以将Python编写成更快、更高效的C语言的模块。虽然Python的自由和开放性促进了广泛的采用和发展,尤其是在数据科学和其他计算量大的领域,但这种自由是以效率低下为代价的。在C中,编码人员有义务提供有关代码执行的更多信息,这是一项可以加快速度的繁重工作。通过将我们的Python代码编写为高效的C结构和方法,您可以使其更加高效,甚至不需要知道C是什么!cdef关键字将变量声明为静态类型的C变量。使用这些C变量允许更快的代码执行,因为变量本身具有指定的类型,而不是Python中的类型值。例如,在Python中,您可以在一行中将同一变量设置为整数,在另一行中将其设置为字符串。例如,a="helloworld"&a=1。但是,在C中,只有静态类型的变量具有一种数据类型。这种刚性意味着可以避免Python的动态类型所需的巨大内存空间开销。因为一个变量可以有很多可能的值,所以需要分配更多的内存。另一方面,严格限制静态类型变量的范围意味着内存空间和执行过程更加高效。如上所述,函数参数也可以声明为静态类型的C变量。这就是为什么简单地声明变量的类型可以大大减少程序处理代码所花费的时间。虽然有许多其他方法可以通过Python代码使Cython更高效,但最简单、技术含量最低且最有价值的方法是写出变量类型。在您的脚本中有无数的Cython应用程序。下次您需要编写逐行函数以应用于具有数千行的数据帧以进行复杂的数据操作时,请记住使用Cython来减少遍历所有行所需的时间。如果您正在手动编写数据转换管道以应用复杂和/或条件扩充,还请记住考虑它是否可以在Cython中实现。在为神经网络编写自定义优化器或损失函数(或自行实现现有函数)时,使用Cython可以加快训练过程。