Tôi đã viết hàm Python tính các tương tác điện từ theo cặp giữa một số lượng lớn (N ~ 10^3) hạt và lưu trữ kết quả trong một NxN complex128 ndarray. Nó chạy, nhưng nó là phần chậm nhất của một chương trình lớn hơn, mất khoảng 40 giây khi N = 900 [sửa]. Mã gốc trông như thế này:Tốc độ Cython không lớn như mong đợi
import numpy as np
def interaction(s,alpha,kprop): # s is an Nx3 real array
# alpha is complex
# kprop is float
ndipoles = s.shape[0]
Amat = np.zeros((ndipoles,3, ndipoles, 3), dtype=np.complex128)
I = np.array([[1,0,0],[0,1,0],[0,0,1]])
im = complex(0,1)
k2 = kprop*kprop
for i in range(ndipoles):
xi = s[i,:]
for j in range(ndipoles):
if i != j:
xj = s[j,:]
dx = xi-xj
R = np.sqrt(dx.dot(dx))
n = dx/R
kR = kprop*R
kR2 = kR*kR
A = ((1./kR2) - im/kR)
nxn = np.outer(n, n)
nxn = (3*A-1)*nxn + (1-A)*I
nxn *= -alpha*(k2*np.exp(im*kR))/R
else:
nxn = I
Amat[i,:,j,:] = nxn
return(Amat.reshape((3*ndipoles,3*ndipoles)))
tôi chưa bao giờ sử dụng trước đó Cython, nhưng điều đó dường như là một nơi tốt để bắt đầu trong nỗ lực của tôi để tăng tốc, vì vậy tôi khá nhiều một cách mù quáng thích nghi các kỹ thuật tôi tìm thấy trong trực tuyến hướng dẫn. Tôi đã có một số tăng tốc (30 giây so với 40 giây), nhưng không gần như là kịch tính như tôi mong đợi, vì vậy tôi tự hỏi liệu tôi đang làm điều gì đó sai hoặc đang thiếu một bước quan trọng. Sau đây là nỗ lực hết sức mình tại cythonizing thói quen trên:
import numpy as np
cimport numpy as np
DTYPE = np.complex128
ctypedef np.complex128_t DTYPE_t
def interaction(np.ndarray s, DTYPE_t alpha, float kprop):
cdef float k2 = kprop*kprop
cdef int i,j
cdef np.ndarray xi, xj, dx, n, nxn
cdef float R, kR, kR2
cdef DTYPE_t A
cdef int ndipoles = s.shape[0]
cdef np.ndarray Amat = np.zeros((ndipoles,3, ndipoles, 3), dtype=DTYPE)
cdef np.ndarray I = np.array([[1,0,0],[0,1,0],[0,0,1]])
cdef DTYPE_t im = complex(0,1)
for i in range(ndipoles):
xi = s[i,:]
for j in range(ndipoles):
if i != j:
xj = s[j,:]
dx = xi-xj
R = np.sqrt(dx.dot(dx))
n = dx/R
kR = kprop*R
kR2 = kR*kR
A = ((1./kR2) - im/kR)
nxn = np.outer(n, n)
nxn = (3*A-1)*nxn + (1-A)*I
nxn *= -alpha*(k2*np.exp(im*kR))/R
else:
nxn = I
Amat[i,:,j,:] = nxn
return(Amat.reshape((3*ndipoles,3*ndipoles)))
Numpy là thư viện C. Và sử dụng BLAS để làm đại số, vì vậy nó khá nhanh. Tôi không thực sự hiểu làm thế nào cython internals hoạt động, nhưng được numpy đã C mã, đạt được trong tốc độ là trong bất cứ điều gì "không gumpy". –
Tôi giả định rằng đủ các hoạt động theo từng dòng trong vòng lặp lồng nhau yêu cầu lời gọi trực tiếp của trình thông dịch Python và do đó các dòng đó có thể là chi phí chủ đạo liên quan đến Numpy - nhưng có lẽ không? –
Bạn có thể thử nhập các mảng cứng nhắc của mình để trình biên dịch biết các loại bên trong mảng. Tuy nhiên, không chắc chắn sự khác biệt lớn như thế nào. Bạn có thể muốn chạy một hồ sơ trên mã python để xem nơi bạn đang thực sự mất tốc độ. Nếu phần lớn thời gian được chi tiêu trong các thói quen sần sùi, bạn sẽ không thu được nhiều tiền bằng cách sử dụng cython. – cel