【发布时间】:2018-04-17 22:16:19
【问题描述】:
在大量使用 numba 之后,我将回到 cython 来并行化一些耗时的函数。以下是一个基本示例:
import numpy as np
cimport numpy as np
from cython import boundscheck, wraparound
from cython.parallel import parallel, prange
@boundscheck(False)
@wraparound(False)
def cytest1(double[:,::1] a, double[:,::1] b, int ix1, int ix2, int iz1, int iz2):
cdef int ix
cdef int iz
for ix in range(ix1, ix2):
for iz in range(iz1, iz2):
b[ix, iz] = 0.5*(a[ix+1, iz] - a[ix-1, iz])
return b
@boundscheck(False)
@wraparound(False)
def cytest2(double[:,::1] a, double[:,::1] b, int ix1, int ix2, int iz1, int iz2):
cdef int ix
cdef int iz
with nogil, parallel():
for ix in prange(ix1, ix2):
for iz in range(iz1, iz2):
b[ix, iz] = 0.5*(a[ix+1, iz] - a[ix-1, iz])
return b
编译这两个函数时(带有openmp标志),并调用它们如下:
nx, nz = 1024, 1024
a = np.random.rand(nx, nz)
b = np.zeros_like(a)
Nit = 1000
ti = time.time()
for i in range(Nit):
cytest1(a, b, 5, nx-5, 0, nz)
print('cytest1 : {:.3f} s.'.format(time.time() - ti))
ti = time.time()
for i in range(Nit):
cytest2(a, b, 5, nx-5, 0, nz)
print('cytest2 : {:.3f} s.'.format(time.time() - ti))
我获得了这些执行时间:
cytest1 : 1.757 s.
cytest2 : 1.861 s.
执行并行函数时,我可以看到我的 4 个 cpu-s 在运行,但执行时间几乎与使用串行函数获得的相同。我试图将prange 移动到内部循环,但结果最差。我还尝试了一些不同的schedule 选项,但没有成功。
我显然遗漏了一些东西,但是什么? prange 是否无法使用试图访问 n+X/n-X 个元素的代码来分块循环?
编辑:
我的设置:
model name : Intel(R) Core(TM) i7-6600U CPU @ 2.60GHz
MemTotal : 8052556 kB
Python : 3.5.2
cython : 0.28.2
Numpy : 1.14.2
Numba : 0.37.0
setup.py:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [
Extension("stencil",
["stencil.pyx"],
libraries=["m"],
extra_compile_args=["-O3", "-ffast-math", "-march=native", "-fopenmp"],
extra_link_args=['-fopenmp'],
)
]
setup(
name="stencil",
cmdclass={"build_ext": build_ext},
ext_modules=ext_modules
)
【问题讨论】:
-
这是一个内存绑定的任务,因此并行化没有帮助,因为它不会增加内存带宽。更糟糕的是:它有一些开销,这使它变慢或可能导致更多的缓存未命中。到目前为止,我的理论..您可以通过在公式中使用诸如 sin 或 cos 之类的 cpu 重的东西来测试它,看看在这种情况下并行化是否有一些好处。
-
实际上,在我的机器上,每次调用您的代码我有 2.9 毫秒与 0.27 毫秒。所以有一个加速。
-
在 Core i7-4771 上,我得到 1.6s 的单线程和 1.0s 的多线程方法。 (Numba 0.38RC1)。因此,如果您没有最差的处理器或 RAM,则应该有优化潜力。
-
@ead 你在哪台机器上? (工作系统/处理器/编译器,..)我得到了与 Numba 和 Cython 完全相同的结果(1.4-1.6 ms/1 ms)。我在 Windows,Python 3.6,MSVCv.1900 上。
-
@max9111 我有 Windows,Intel Xeon E5-2620 @ 2.1 Ghz,Python 3.6,Cython 0.27