在 Cython 中填充 64 位 numpy 数组比 32 位数组慢

Filling 64 bit numpy array in Cython slower than 32 bit array

我想了解为什么填充 64 位数组比填充 32 位数组慢。

示例如下:

@cython.boundscheck(False)
@cython.wraparound(False)
def test32(long long int size):
   cdef np.ndarray[np.int32_t,ndim=1] index = np.zeros(size, np.int32)
   cdef Py_ssize_t i

   for i in range(size):
       index[i] = i

   return indx

@cython.boundscheck(False)
@cython.wraparound(False)
def test64(long long int size):
   cdef np.ndarray[np.int64_t,ndim=1] index = np.zeros(size, np.int64)
   cdef Py_ssize_t i

   for i in range(size):
       index[i] = i

   return indx

时间:

In [4]: %timeit test32(1000000)
1000 loops, best of 3: 1.13 ms over loop

In [5]: %timeit test64(1000000)
100 loops, best of 3: 2.04 ms per loop

我正在使用 64 位计算机和用于 Python (9.0) 编译器的 Visual C++。

编辑:

初始化 64 位数组和 32 位数组似乎花费相同的时间,这意味着时间差异是由于填充过程造成的。

In [8]: %timeit np.zeros(1000000,'int32')
100000 loops, best of 3: 2.49 μs per loop

In [9]: %timeit np.zeros(1000000,'int64')
100000 loops, best of 3: 2.49 μs per loop

编辑2:

正如 DavidW 指出的那样,可以使用 np.arange 复制此行为,这意味着这是预期的:

In [7]: %timeit np.arange(1000000,dtype='int32')
10 loops, best of 3: 1.22 ms per loop

In [8]: %timeit np.arange(1000000,dtype='int64')
10 loops, best of 3: 2.03 ms per loop

一组快速测量(我最初在评论中发布)表明您看到 np.fullnp.onesnp.ones 非常相似的行为(64 位占用的时间是 32 位的两倍) np.arange,所有三个显示的时间彼此相似(arange 对我来说比其他两个慢 10%)。

我相信这表明这是预期的行为,只是填充内存所需的时间。 (64 位的内存显然是 32 位的两倍)。

那么有趣的问题是为什么 np.zeros 如此统一(和快速)——一个完整的答案可能在 this C-based question 中给出,但基本的总结是分配零(如 C function calloc) 可以懒惰地完成 - 即它实际上不会分配或填充太多,直到你真正尝试写入内存。