ant*_*ony 10 cython auto-vectorization
请考虑以下最小示例:
#cython: language_level=3, boundscheck=False, wraparound=False, initializedcheck=False, cdivision=True
cimport cython
from libc.stdlib cimport malloc
def main(size_t ni, size_t nt, size_t nx):
cdef:
size_t i, j, t, x, y
double[:, :, ::1] a = <double[:ni, :ni, :nx]>malloc(ni * ni * nx * sizeof(double))
double[:, :, ::1] b = <double[:nt, :ni, :nx]>malloc(nt * ni * nx * sizeof(double))
size_t[:, :, ::1] best = <size_t[:nt, :ni, :nx]>malloc(nt * ni * nx * sizeof(size_t))
size_t mxi
double s, mxs
for t in range(nt):
for j in range(ni):
for y in range(nx): # this loops does nothing but is needed for the effect below.
mxs = -1e300
for i in range(ni):
for x in range(nx):
with cython.boundscheck(False): # Faster!?!?
s = b[t, i, x] + a[i, j, x]
if s >= mxs:
mxs = s
mxi = i
best[t + 1, j, y] = mxi
return best[0, 0, 0]
Run Code Online (Sandbox Code Playgroud)
基本上沿着某些特定轴对两个2D阵列求和,并沿另一个轴找到最大化指数.
当使用gcc -O3编译并使用参数(1,2000,2000)调用时,添加boundscheck = True会导致执行速度比boundscheck = False快两倍.
任何暗示为什么会这样的情况?(好吧,我可以猜测这与GCC自动向量化有关......)
提前致谢.
(从cython用户交叉发布)
Boundscheck 是一种安全检查,检查您正在访问向量边界内的索引。\n如果您不费心检查索引是否会超出范围,那么速度会更快。执行检查需要时间。
\n\n也就是说,如果boundcheck为true,它将在读取或写入内存之前检查索引是否在向量的范围内。如果不是,它会抛出一个错误。如果boundcheck为假,即使索引越界,它也会读取或写入指针,通过读取和写入内存给出错误数据,通过写入破坏数据。
\n\n来自文档:
\n\n\n\n\n数组查找仍然因两个因素而变慢:
\n\n1) 进行边界检查。
\n\n2) 正确检查并处理负索引。
\n
未绑定检查的后果是:
\n\n\n\n\n现在不执行边界检查(并且,作为副作用,如果您 \xe2\x80\x98\xe2\x80\x99do\xe2\x80\x99\xe2\x80\x99 碰巧访问出界,您将在最好的情况是程序崩溃,最坏的情况是数据损坏)。
\n
尤其重要的是你可以没有向量。这是文档中的警告:
\n\n\n\n\n警告
\n\n速度是有一定成本的。尤其是,将类型化对象(例如示例代码中的 f、g 和 h)设置为 None 可能会很危险。将此类对象设置为 None 是完全合法的,但您对它们所能做的就是检查它们是否为 None。所有其他用途(属性查找或索引)可能会出现段错误或损坏数据(而不是像在 Python 中那样引发异常)。
\n\n实际的规则有点复杂,但主要信息很明确:在不知道类型化对象未设置为 None 的情况下,不要使用它们。
\n
http://docs.cython.org/src/userguide/numpy_tutorial.html
\n