Python 如何使用cython使我的代码更高效?

Python 如何使用cython使我的代码更高效?,python,numpy,cython,Python,Numpy,Cython,我已经用Python编写了以下代码。 如果我使用此代码,需要1分钟20秒: def calc_cy(searchX,searchY,searchZ,dx,dz,r_vector,p_true,a_factor,sim): calc1 = np.full((len(searchX),len(searchY),len(searchZ)),np.nan) z_t = np.abs(np.ceil(r_vector[:,2]/dz).squeeze()) for ix in searchX:

我已经用Python编写了以下代码。 如果我使用此代码,需要1分钟20秒:

def calc_cy(searchX,searchY,searchZ,dx,dz,r_vector,p_true,a_factor,sim):

calc1 = np.full((len(searchX),len(searchY),len(searchZ)),np.nan)
z_t = np.abs(np.ceil(r_vector[:,2]/dz).squeeze())

for ix in searchX:
    for iy in searchY:
        for iz in searchZ:
            dt=[]
            ir = (np.floor((((ix-r_vector[:,0])**2+(iy-r_vector[:,1])**2))**0.5)) 
            for ip in range(p_true.size):
                dt.append(sim[int(iz)][int(ir[ip]),int(z_t[ip])])

            dt_sim = dt-min(dt)
            dt_true=p_true-min(p_true[0])
            calc1[int(ix),int(iy),int(iz)]=np.linalg.norm(a_factor*(dt_sim-dt_true))
return calc1
如果我将此代码用于Cython,则需要1分钟5秒:

设置代码:

from distutils.core import setup
from Cython.Build import cythonize
import numpy

setup(ext_modules = cythonize("calc_cy.pyx"), include_dirs = [numpy.get_include()])
使用Cython的代码:

import numpy as np
cimport numpy as np
import math

DTYPE = np.double
ctypedef np.double_t DTYPE_t

def calc_cy(np.ndarray [DTYPE_t,ndim = 3] sim,np.ndarray [DTYPE_t,ndim = 1] searchX,np.ndarray [DTYPE_t,ndim = 1] searchY,np.ndarray [DTYPE_t,ndim = 1] searchZ,np.ndarray [DTYPE_t,ndim = 2] r_vector,np.ndarray [DTYPE_t,ndim = 1] p_true,np.ndarray [DTYPE_t,ndim = 1] a_factor):

    cdef np.ndarray[DTYPE_t,ndim = 3] calc1 = np.zeros((len(searchX),len(searchY),len(searchZ)),dtype = DTYPE)
    cdef np.ndarray[DTYPE_t,ndim = 1] dt2 = np.zeros(len(p_true),dtype = DTYPE)
    cdef np.ndarray[DTYPE_t,ndim = 1] dt_sim = np.zeros(len(dt2),dtype = DTYPE)
    cdef np.ndarray[DTYPE_t,ndim = 1] dt_picks = np.zeros(len(p_true),dtype = DTYPE)

    cdef int ir
    cdef int k
    cdef int m

    for ix in range(len(searchX)):
        for iy in range(len(searchY)):
            for iz in range(len(searchZ)):
                for ip in range(len(p_true)):
                    ir= int(np.floor((((searchX[ix]-r_vector[ip,0])**2+(searchY[iy]-r_vector[ip,1])**2))**0.5))
                    k = int(searchZ[iz])
                    m = int(math.fabs(math.ceil(r_vector[ip,2])))
                    dt2[int(ip)] = sim[k,ir,m]
                dt_sim = dt2- min(dt2)
                dt_true = p_true - min(p_true)
                calc1[ix,iy,iz] = np.linalg.norm(a_factor*(dt_sim-dt_true))
    return calc1
如何改进代码并使其更高效?
谢谢

查看您的代码,
ir
的值不依赖于
iz
,因此您可以将其移出
iz
循环。
dt_true
的值仅取决于
p_true
,因此只需计算一次。 这些组合将消除不必要的重新计算,从而加快代码的速度。(这称为。)

此外,您还可以将
dt
的计算转换为列表理解。这将加快Python版本的速度。不过,我不确定这是否会对Cython版本有所帮助

这将使代码看起来像这样:

def calc_cy(searchX,searchY,searchZ,dx,dz,r_vector,p_true,a_factor,sim):
    calc1 = np.full((len(searchX),len(searchY),len(searchZ)),np.nan)
    z_t = np.abs(np.ceil(r_vector[:,2]/dz).squeeze())
    dt_true = p_true - min(p_true[0])
    for ix in searchX:
        for iy in searchY:
            ir = np.floor(((ix-r_vector[:,0])**2+(iy-r_vector[:,1])**2)**0.5)
            for iz in searchZ:
                dt = [sim[int(iz)][int(ir[ip]),int(z_t[ip])] for ip in range(p_true.size)]
                dt_sim = dt-min(dt)
                calc1[int(ix),int(iy),int(iz)]=np.linalg.norm(a_factor*(dt_sim-dt_true))
    return calc1

假设您有一个多核CPU,您可以生成
searchX
searchY
的所有可能组合的元组。然后使用
multiprocessing.Pool
concurrent.futures.ProcessPoolExecutor
可以将
searchY
循环中的计算划分到所有核心上,因为它们是独立的。如果您有n个内核,那么运行时应该减少大约n倍。

在numpy例程中花费的时间可能是问题所在。编译其余的不会有什么不同。你也有4个叠瓦环。。。顺便说一句,您可以删除索引。直接迭代元素而不是索引:
用于范围内的ix(len(searchX)):
=>
用于searchX中的x
,并使用
x
而不是
searchX[ix]
,这样可以保存列表访问权。@Cython中的Jean Françoisfare(与Python相反)索引通常比直接迭代好。同意你所说的其余内容wrote@DavidW是的,对于内部循环变量可能是这样(OP可能知道这一事实,因为python版本不使用该反模式)。但不是针对内部循环中不改变的ix/iy变量。但在这之后,C优化器可以检测到这一点并创造奇迹。我如何改进我的代码并使其更高效?对其进行基准测试,对其进行分析。我们不能这样做,因为我们缺少运行程序的代码/数据。也没有对程序功能的解释,而h使事情变得更加困难。请参阅:。