我正在尝试使用Cython加速以下代码。从python导入两个参数:
processing_times:列出500个列表,每个列表包含20个整数(500x20)。
序列:列出500个整数。
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef taillard_acceleration(sequence, processing_times, int job_inserted, int num_machines):
# Static arrays - number of jobs limited to 500 jobs and 20 machines
cdef int e[501][21]
cdef int q[501][21]
cdef int f[501][21]
cdef int ms[501]
# Variables
cdef int sequence_length, best_makespan, best_position
cdef int i, j, iq, jq, tmp
# Initialize some values
sequence_length = len(sequence)
iq = sequence_length + 1
for i in range(1, sequence_length + 2):
if i < sequence_length + 1:
e[i][0] = 0
# Q index I
iq = iq - 1
q[iq][num_machines + 1] = 0
f[i][0] = 0
jq = num_machines + 1
for j in range(1, num_machines + 1):
if i == 1:
e[0][j] = 0
q[sequence_length + 1][num_machines + 1 - j] = 0
if i < sequence_length + 1:
# Q Index J
jq = jq - 1
if e[i][j - 1] > e[i - 1][j]:
e[i][j] = e[i][j - 1] + processing_times[sequence[i - 1]-1][j-1]
else:
e[i][j] = e[i - 1][j] + processing_times[sequence[i - 1]-1][j-1]
if q[iq][jq + 1] > q[iq + 1][jq]:
q[iq][jq] = q[iq][jq + 1] + processing_times[sequence[iq - 1]-1][jq-1]
else:
q[iq][jq] = q[iq + 1][jq] + processing_times[sequence[iq - 1]-1][jq-1]
# f(ij) = max {f(i, j-1), e(i-1, j)}
if f[i][j - 1] > e[i - 1][j]:
f[i][j] = f[i][j - 1] + processing_times[job_inserted-1][j-1]
else:
f[i][j] = e[i - 1][j] + processing_times[job_inserted-1][j-1]
# Makespam - job k in position i
best_makespan = 0
best_position = 0
for i in range(1, sequence_length + 2):
ms[i] = 0
for j in range(1, num_machines + 1):
tmp = f[i][j] + q[i][j]
if tmp > ms[i]:
ms[i] = tmp
# Check best insertion position
if ms[i] < best_makespan or best_makespan == 0:
best_makespan = ms[i]
best_position = i
return best_position, best_makespan
我能够比原来的python代码快4倍:
Just Python: 0.04114614830813535
With Cython: 0.00937230621550278
Cython is 4.390183948543561 times faster
如何在此代码中获得更好的速度提升?
我已经尝试将sequence和processing_times转换为numpy数组,然后使用Memory视图,但我没有改进。
cpdef taillard_acceleration(sequence_np, processing_times_np, int job_inserted, int num_machines):
# memory view
cdef int [:, :] processing_times = processing_times_np
cdef int [:] sequence = sequence_np
我还应该为q,e,f,ms数组使用malloc吗?第一次使用Cython,所以我不知道我是否正确行事。非常感谢任何帮助。
答案 0 :(得分:1)
大部分看起来都是正确输入的,所以你不太可能获得巨大的改进。未键入的主要内容是sequence
和processing_times
。你应该做这些记忆:
def taillard_acceleration(int[:] sequence, int[:,:] processing_times, int job_inserted, int num_machines):
我知道您已尝试过此操作,但您还应将其索引更改为processing_times[i,j]
(而不是processing_times[i][j]
)。你正在做的是创建一维内存视图作为临时对象,可能会慢一些。
对于q
,e
,f
和ms
数组:如果您乐意重新编译以更改大小,那么您现在正在做的事情绝对没问题。如果您认为可能希望在运行时更改大小,则应在运行时分配它们。您可以使用malloc
,但我会使用:
cdef int[:,::1] e = np.zeros((501,21))
([:,::1]
告诉Cython数组是2D和连续的)。像这样使用numpy会比malloc
慢一点,但它也更容易,而且你错误的可能性也大大降低。如果您这样做,请按照上述说明将其索引更改为e[i,j]
。
(它看起来真的应该是sequency_length
的大小num_machines
所以运行时大小可能是一个好主意)