Я пытаюсь ускорить мой код с помощью cython. После перевода кода на cython из python я вижу, что я не получил никакой скорости. Я думаю, что источником проблемы является плохая производительность, которую я получаю с помощью массивов numpy в cython.Cython: медленные массивы numpy
я придумал очень простую программу, чтобы показать это:
############### test.pyx #################
import numpy as np
cimport numpy as np
cimport cython
def func1(long N):
cdef double sum1,sum2,sum3
cdef long i
sum1 = 0.0
sum2 = 0.0
sum3 = 0.0
for i in range(N):
sum1 += i
sum2 += 2.0*i
sum3 += 3.0*i
return sum1,sum2,sum3
def func2(long N):
cdef np.ndarray[np.float64_t,ndim=1] sum_arr
cdef long i
sum_arr = np.zeros(3,dtype=np.float64)
for i in range(N):
sum_arr[0] += i
sum_arr[1] += 2.0*i
sum_arr[2] += 3.0*i
return sum_arr
def func3(long N):
cdef double sum_arr[3]
cdef long i
sum_arr[0] = 0.0
sum_arr[1] = 0.0
sum_arr[2] = 0.0
for i in range(N):
sum_arr[0] += i
sum_arr[1] += 2.0*i
sum_arr[2] += 3.0*i
return sum_arr
##########################################
################## test.py ###############
import time
import test as test
N = 1000000000
for i in xrange(10):
start = time.time()
sum1,sum2,sum3 = test.func1(N)
print 'Time taken = %.3f'%(time.time()-start)
print '\n'
for i in xrange(10):
start = time.time()
sum_arr = test.func2(N)
print 'Time taken = %.3f'%(time.time()-start)
print '\n'
for i in xrange(10):
start = time.time()
sum_arr = test.func3(N)
print 'Time taken = %.3f'%(time.time()-start)
############################################
И из питона test.py я получаю:
Time taken = 1.445
Time taken = 1.433
Time taken = 1.434
Time taken = 1.428
Time taken = 1.449
Time taken = 1.425
Time taken = 1.421
Time taken = 1.451
Time taken = 1.483
Time taken = 1.418
Time taken = 2.623
Time taken = 2.603
Time taken = 2.977
Time taken = 3.237
Time taken = 2.748
Time taken = 2.798
Time taken = 2.811
Time taken = 2.783
Time taken = 2.585
Time taken = 2.595
Time taken = 1.503
Time taken = 1.529
Time taken = 1.509
Time taken = 1.543
Time taken = 1.427
Time taken = 1.425
Time taken = 1.423
Time taken = 1.415
Time taken = 1.414
Time taken = 1.418
Мой вопрос: почему func2 почти 2x медленнее чем func1 и func3?
Есть ли способ улучшить это?
Спасибо!
######## UPDATEМоя настоящая проблема заключается в следующем. Я вызываю функцию, которая принимает 3D-массив (например, P [i, j, k]). Функция будет проходить через каждый элемент и вычислять несколько величин: величину, которая зависит от значения массива в этой позиции (например, A = f (P [i, j, k])) и других величин, которые зависят только от позиции самого массива (B = g (i, j, k)). Схематически все будет выглядеть так:
for i in xrange(N):
corr1 = h(i,val)
for j in xrange(N):
corr2 = h(j,val)
for k in xrange(N):
corr3 = h(k,val)
A = f(P[i,j,k])
B = g(i,j,k)
Arr[B] += A*corr1*corr2*corr3
где val является свойством 3D-массива, представленного рядом. Это число может быть различным для разных полей.
Поскольку я должен выполнять эту операцию по многим 3D-массивам, я бы подумал, что было бы лучше, если бы я создал новую процедуру, которая принимает множество различных входных 3D-массивов, оставляя количество неизвестных априорных массивов. Идея состоит в том, что, поскольку B будет точно таким же во всех массивах, я могу избежать вычисления его для каждого массива и только вычислить его один раз. Проблема заключается в том, что corr1, corr2, corr3 выше станет массивами:
Если у меня есть ряд 3D-массивы, равных num_3D_arrays я делаю что-то как:
for i in xrange(N):
for p in xrange(num_3D_arrays):
corr1[p] = h(i,val[p])
for j in xrange(N):
for p in xrange(num_3D_arrays):
corr2[p] = h(j,val[p])
for k in xrange(N):
for p in xrange(num_3D_arrays):
corr3[p] = h(k,val[p])
B = g(i,j,k)
for p in xrange(num_3D_arrays):
A[p] = f(P[i,j,k])
Arr[p,B] += A[p]*corr1[p]*corr2[p]*corr3[p]
Так вал, что я меняюсь переменные corr1, corr2, corr3 и A от скаляра к массивам убивают производительность, которую я ожидал бы избежать большого цикла.
#
код 'для i в диапазоне (N): sum_arr [0] + = i sum_arr [1] + = 2.0 * i sum_arr [2] + = 3.0 * i' игнорирует все, что имеет значение numpy. Numpy не быстро, потому что вы можете быстро получить доступ к индексам, но потому, что он может быстро выполнять числовые операции. Но не так. Я бы рекомендовал читать в numpy –
И я полагаю, что было бы сложно сделать это быстрее. Поскольку при условии, что вы достаточно упрямы, чтобы использовать 'numpy', вам нужно создать массив numpy в этом цикле и сделать np.sum(), но создание массива numpy, вероятно, является самым медленным в этом фрагменте. Я также рекомендую проверять каждую линию отдельно вместо этого простого тайм-кода. ** [некоторые чтения по профилированию] (http://stackoverflow.com/questions/582336/how-can-you-profile-a-script) ** –
ОК спасибо! Проблема в моем случае состоит в том, что я не могу определить отдельные переменные, как в func1, но мне нужно определить массив размера, который я не знаю априори. Есть ли другой способ сделать это, чем использовать массив numpy? – Francisco