详解如何利用Cython为Python代码加速
引言
通常,在Python中写循环(特别是多重循环)非常的慢,在文章https://www.nhooo.com/article/133807.htm中,我们的元胞自动机的状态更新函数update_state使用了两重循环,所以我们尝试用Cython重构该方法。
代码
我们在同文件夹下新建一个update.pyx文件,写入如下内容
importnumpyasnp cimportnumpyasnp cimportcython DTYPE=np.float ctypedefnp.float_tDTYPE_t defupdate_state(np.ndarray[DTYPE_t,ndim=2]cells): returnupdate_state_c(cells) @cython.boundscheck(False) @cython.wraparound(False) cdefnp.ndarray[DTYPE_t,ndim=2]update_state_c(np.ndarray[DTYPE_t,ndim=2]cells): """更新一次状态""" cdefunsignedinti cdefunsignedintj cdefnp.ndarray[DTYPE_t,ndim=2]buf=np.zeros((cells.shape[0],cells.shape[1]),dtype=DTYPE) cdefDTYPE_tneighbor_num foriinrange(1,cells.shape[0]-1): forjinrange(1,cells.shape[0]-1): #计算该细胞周围的存活细胞数 neighbor_num=cells[i,j-1]+cells[i,j+1]+cells[i+1,j]+cells[i-1,j]+\ cells[i-1,j-1]+cells[i-1,j+1]+\ cells[i+1,j-1]+cells[i+1,j+1] ifneighbor_num==3: buf[i,j]=1 elifneighbor_num==2: buf[i,j]=cells[i,j] else: buf[i,j]=0 returnbuf
update_state_c函数上的两个装饰器是用来关闭Cython的边界检查的。
在同文件下新建一个setup.py文件
importnumpyasnp fromdistutils.coreimportsetup fromCython.Buildimportcythonize setup( name="CythonUpdateState", ext_modules=cythonize("update.pyx"), include_dirs=[np.get_include()] )
因为在Cython文件中使用了NumPy的头文件,所以我们需要在setup.py将其包含进去。
执行pythonsetup.pybuild_ext--inplace后,同文件夹下会生成一个update.cp36-win_amd64.pyd的文件,这就是编译好的C扩展。
我们修改原始的代码,首先在文件头部加入importupdateascupdate,然后修改更新方法如下
defupdate_state(self): """更新一次状态""" self.cells=cupdate.update_state(self.cells) self.timer+=1
将原方法名就改为update_state_py即可,运行脚本,无异常。
测速
我们编写一个方法来测试一下使用Cython可以带来多少速度的提升
deftest_time(): importtime game=GameOfLife(cells_shape=(60,60)) t1=time.time() for_inrange(300): game.update_state() t2=time.time() print("CythonUseTime:",t2-t1) delgame game=GameOfLife(cells_shape=(60,60)) t1=time.time() for_inrange(300): game.update_state_py() t2=time.time() print("NativePythonUseTime:",t2-t1)
运行该方法,在我的电脑上输出如下
CythonUseTime:0.007000446319580078
NativePythonUseTime:4.342248439788818
速度提升了600多倍。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。