cython boundscheck = True比boundscheck = False快

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用户交叉发布)

pat*_*_ai 0

Boundscheck 是一种安全检查,检查您正在访问向量边界内的索引。\n如果您不费心检查索引是否会超出范围,那么速度会更快。执行检查需要时间。

\n\n

也就是说,如果boundcheck为true,它将在读取或写入内存之前检查索引是否在向量的范围内。如果不是,它会抛出一个错误。如果boundcheck为假,即使索引越界,它也会读取或写入指针,通过读取和写入内存给出错误数据,通过写入破坏数据。

\n\n

来自文档:

\n\n
\n

数组查找仍然因两个因素而变慢:

\n\n

1) 进行边界检查。

\n\n

2) 正确检查并处理负索引。

\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
\n\n

http://docs.cython.org/src/userguide/numpy_tutorial.html

\n

  • 我认为提出这个问题的原因是在这种情况下 `boundscheck(True)` 更快,这是违反直觉的。 (8认同)