如何使用fortran和ctypes?
elementwise.F90:
subroutine elementwise(a, b, c, M, N) bind(c, name='elementwise')
use iso_c_binding, only: c_float, c_int
integer(c_int),intent(in) :: M, N
real(c_float), intent(in) :: a(M, N), b(M, N)
real(c_float), intent(out):: c(M, N)
integer :: i,j
forall (i=1:M,j=1:N)
c(i,j) = a(i,j) * b(i,j)
end forall
end subroutine
elementwise.py:
from ctypes import CDLL, POINTER, c_int, c_float
import numpy as np
import time
fortran = CDLL('./elementwise.so')
fortran.elementwise.argtypes = [ POINTER(c_float),
POINTER(c_float),
POINTER(c_float),
POINTER(c_int),
POINTER(c_int) ]
# Setup
M=10
N=5000000
a = np.empty((M,N), dtype=c_float)
b = np.empty((M,N), dtype=c_float)
c = np.empty((M,N), dtype=c_float)
a[:] = np.random.rand(M,N)
b[:] = np.random.rand(M,N)
# Fortran call
start = time.time()
fortran.elementwise(a.ctypes.data_as(POINTER(c_float)),
b.ctypes.data_as(POINTER(c_float)),
c.ctypes.data_as(POINTER(c_float)),
c_int(M), c_int(N))
stop = time.time()
print 'Fortran took ',stop - start,'seconds'
# Numpy
start = time.time()
c = np.multiply(a,b)
stop = time.time()
print 'Numpy took ',stop - start,'seconds'
予编译使用
gfortran -O3 -funroll-loops -ffast-math -floop-strip-mine -shared -fPIC \
-o elementwise.so elementwise.F90
输出的文件的Fortran产生的加速〜10 %:
$ python elementwise.py
Fortran took 0.213667869568 seconds
Numpy took 0.230120897293 seconds
$ python elementwise.py
Fortran took 0.209784984589 seconds
Numpy took 0.231616973877 seconds
$ python elementwise.py
Fortran took 0.214708089828 seconds
Numpy took 0.25369310379 seconds
'numexpr'可以一枝独秀'像这样ufunc般的操作numpy',尤其是几个串在一起。另外,如果您有多个内核,请尝试设置'ne.set_num_cores(N)',其中'N'是您的计算机的核心数。 – askewchan
在我的机器上,基于'numexpr'的函数比在单个内核上运行的'np.multiply()'运行速度慢大约15%,但是当我将内核数量设置为8时,它的速度会降低大约2倍。记住,你可能会发现你必须重置你的Python进程的核心关系才能使用多个核心 - [请参阅我的答案](http://stackoverflow.com/a/15641148/1461210)。 –
您可以尝试使用[Theano]使用您的GPU(https://github.com/Theano/Theano)。我真的不知道它是否会有所帮助,结果将取决于您的确切硬件,但它可能值得一试。 [这里](https://groups.google.com/forum/#!topic/theano-users/fZpCchn4JbI)你会找到一个如何使用Theano进行元素矩阵乘法的例子。 –