使用 Cython 优化 Python 代码是一种常见的方式,通过将 Python 代码转译为 C 并编译,可以显著提高性能。Cython 是 Python 的超集,允许在代码中直接使用 C 类型声明,从而加速计算密集型任务。
问题背景
我有一个用Python编写的相对较大的代码,运行时需要大约3分钟才能完成全部计算。最终,我想将N增加到大约400,并将for循环中的m更改为更大的数字 - 这可能需要几个小时的计算时间,而我希望减少这个时间。步骤1-6花费的时间很长。当我尝试用Cython(即导入pyximport然后导入我的文件)运行它时,我得到以下错误 FDC.pyx:49:19: 'range’不是有效的Cython语言结构和FDC.pyx:49:19: 'range’不是有效的Cython属性或使用不正确。
解决方案
- 将Python代码转换为Cython代码。为了做到这一点,你可以使用Cython编译器,它可以将Python代码转换为C代码。C代码可以使用C编译器进行编译,生成一个可执行文件。这个可执行文件可以比原始的Python代码运行得更快。
- 使用Cython优化器。Cython优化器可以对Cython代码进行优化,以使其运行得更快。Cython优化器使用各种技术来优化代码,例如内联函数、循环展开和常量传播。
- 使用Cython并行化。Cython支持并行化,这可以让你在多核计算机上运行代码。Cython并行化使用OpenMP库来实现并行化。
以下是用Cython优化Python代码的代码示例:
import numpy as np
cimport numpy as np
def r(x,y): #distance between particles
return np.sqrt(x**2 + y**2)
def FDC(x,y,d=0.01,T=100):
N=len(x)
charge=(x,y)
l=0; m=0; n=0
prevsW = 0.
for q in range(0,100):
T=0.9*T
for m in range(0, 4000): #steps 1 - 6 in notes looped over
xRef = np.random.randint(0,1) #Choosing x or y
yRef = np.random.randint(0,N-1) #choosing the element of xRef
j = charge[xRef][yRef] #Chooses specific axis of a charge and stores it as 'j'
prevops = None #assigns prevops as having no variable
while True: #code to randomly change charge positions and ensure they do not leave the disc
ops =(add, sub); op=np.random.choice(ops)
tempJ = op(j, d)
#print xRef, yRef, n, tempJ
charge[xRef][yRef] = tempJ
ret = r(charge[0][yRef],charge[1][yRef])
if ret<=1.0:
j=tempJ
#print "working", n
break
elif prevops != ops and prevops != None: #!= is 'not equal to' so that if both addition and subtraction operations dont work the code breaks
break
prevops = ops #####
o = 0; k = 0; sW=0 #New energy with altered x coordinate
for o in range(0, N):
for k in range(0, N):
if o==k:
continue
xdist = x[o] - x[k]
ydist = y[o] - y[k]
sW+=0.5/(r( xdist , ydist ))
difference = sW - prevsW
prevsW = sW
#Conditions:
p=0
if difference < 0: #accept change
charge[xRef][yRef] = j
#print 'step 5'
randomnum = np.random.uniform(0,1) #r
if difference > 0: #acceptance with a probability
p = np.exp( -difference / T )
#print 'step 6', p
if randomnum >= p:
charge[xRef][yRef] = op(tempJ, -d) #revert coordinate to original if r>p
#print charge[xRef][yRef], 'r>p'
#print m, charge, difference
o = 0; k = 0; DW=0 #sum of energy for initial charges
for o in range(0, N):
for k in range(0, N):
if o==k:
continue
xdist=x[o]-x[k]
ydist=y[o]-y[k]
DW+= 0.5/(r(xdist,ydist))
return charge, DW
这个代码示例使用Cython编译器将Python代码转换为Cython代码。然后,可以使用Cython优化器对Cython代码进行优化。最后,可以使用Cython并行化来在多核计算机上运行代码。
通过 Cython 优化,可以让 Python 在性能要求高的场景中接近 C 的表现,同时保留高层次的开发便利性。