在python程序中,以下函数被另一个函数调用了大约20,000次,而另一个函数被执行了30次,被调用了大约1000次。因此,调用此特定功能的总次数约为600,000,000。在python中,它需要两个多小时(可能更长;可能会中止程序,而无需等待其完成),而用Java编写的相同任务基本上只需不到5分钟。如果我将20,000以上更改为400(不影响程序其余部分的其他所有内容),则总时间将减少到大约4分钟(这意味着此特定功能是元凶)。我该怎么做才能加快Python版本的速度,或者只是不可能?在此函数内没有操作任何列表(整个程序的其他地方都有列表,但是在那些地方,我尝试尽可能使用numpy数组)。我知道用numpy数组替换python列表可以加快速度,但是在我的程序中(不在此特定函数中)有些情况下,我必须使用append迭代地构建列表。而且这些必备列表是对象列表(不是浮点数或整数),因此即使我将这些对象列表转换为numpy数组,numpy也无济于事。
def compute_something(arr):
'''
arr is received as a numpy array of ints and floats (I think python upcasts them to all floats,
doesn’t it?).
Inside this function, elements of arr are accessed using indexing (arr[0], arr[1], etc.), because
each element of the array has its own unique use. It’s not that I need the array as a whole (as in
arr**2 or sum(arr)).
The arr elements are used in several simple arithmetic operations involving nothing costlier than
+, -, *, /, and numpy.log(). There is no other loop inside this function; there are a few if’s though.
Inside this function, use is made of constants imported from other modules (I doubt the
importing, as in AnotherModule.x is expensive).
'''
for x in numpy.arange(float1, float2, float3):
do stuff
return a, b, c # Return a tuple of three floats
编辑: 感谢所有的评论。这是函数的内部(为方便起见,我将变量名简称)。 ndarray数组arr中只有3个元素。您能提出任何建议吗?
def compute_something(arr):
a = Mod.b * arr[1] * arr[2] + Mod.c
max = 0.0
for c in np.arange(a, arr[1] * arr[2] * (Mod.d – Mod.e), Mod.f):
i = c / arr[2]
m1 = Mod.A * np.log( (i / (arr[1] *Mod.d)) + (Mod.d/Mod.e))
m2 = -Mod.B * np.log(1.0 - (i/ (arr[1] *Mod.d)) - (Mod.d /
Mod.e))
V = arr[0] * (Mod.E - Mod.r * i / arr[1] - Mod.r * Mod.d -
m1 – m2)
p = c * V /1000.0
if p > max:
max = p
vmp = V
pen = Mod.COEFF1 * (Mod.COEFF2 - max) if max < Mod.CONST else 0.0
wo = Mod.COEFF3 * arr[1] * arr[0] + Mod.COEFF4 * abs(Mod.R5 - vmp) +
Mod.COEFF6 * arr[2]
w = wo + pen
return vmp, max, w
答案 0 :(得分:1)
我建议使用range
,因为它快大约2倍:
def python():
for i in range(100000):
pass
def numpy():
for i in np.arange(100000):
pass
from timeit import timeit
print(timeit(python, number=1000))
print(timeit(numpy, number=1000))
输出:
5.59282787179696
10.027646953771665
答案 1 :(得分:1)
Python支持代码分析。 (模块cProfile
)。还可以选择使用line_profiler查找代码tool here中最昂贵的部分。
因此,您无需猜测哪一部分代码最昂贵。
在您假设的这段代码中,问题出在循环的用法上,该循环在对象类型之间生成许多转换。如果使用numpy,则可以向量化计算。
我尝试重写您的代码以向量化您的操作。您没有提供什么是Mod
对象的信息,但是我希望它会起作用。
def compute_something(arr):
a = Mod.b * arr[1] * arr[2] + Mod.c
# start calculation on vectors instead of for lop
c_arr = np.arange(a, arr[1] * arr[2] * (Mod.d – Mod.e), Mod.f)
i_arr = c_arr/arr[2]
m1_arr = Mod.A * np.log( (i_arr / (arr[1] *Mod.d)) + (Mod.d/Mod.e))
m2_arr = -Mod.B * np.log(1.0 - (i_arr/ (arr[1] *Mod.d)) - (Mod.d /
Mod.e))
V_arr = arr[0] * (Mod.E - Mod.r * i_arr / arr[1] - Mod.r * Mod.d -
m1_arr – m2_arr)
p = c_arr * V_arr / 1000.0
max_val = p.max() # change name to avoid conflict with builtin function
max_ind = np.nonzero(p == max_val)[0][0]
vmp = V_arr[max_ind]
pen = Mod.COEFF1 * (Mod.COEFF2 - max_val) if max_val < Mod.CONST else 0.0
wo = Mod.COEFF3 * arr[1] * arr[0] + Mod.COEFF4 * abs(Mod.R5 - vmp) +
Mod.COEFF6 * arr[2]
w = wo + pen
return vmp, max_val, w