Cython:为什么size_t比int快?

the*_*Sin 3 python performance types cython

将某些Cython变量从类型更改int为类型size_t可以显着减少一些函数时间(~30%),但我不明白为什么.

例如:

cimport numpy as cnp
import numpy as np

def sum_int(cnp.int64_t[::1] A):
    cdef unsigned long s = 0
    cdef int k
    for k in xrange(A.shape[0]):
        s += A[k]
    return s

def sum_size_t(cnp.int64_t[::1] A):
    cdef unsigned long s = 0
    cdef size_t k
    for k in xrange(A.shape[0]):
        s += A[k]
    return s

a = np.array(range(1000000))
Run Code Online (Sandbox Code Playgroud)

时间结果如下:

In [17]: %timeit sum_int(a)   
1000 loops, best of 3: 652 µs per loop

In [18]: %timeit sum_size_t(a)
1000 loops, best of 3: 427 µs per loop
Run Code Online (Sandbox Code Playgroud)

我是Cython的新手,比C.更了解Fortran.帮帮我.这两种变量类型之间的重要区别是什么导致了这种性能差异?什么是我不喜欢Cython?

vir*_*tor 9

您可能不得不进行逐行分析以找出确切的结果,但有一件事从我生成的C文件中脱颖而出:int检查版本是否为环绕到负数,size_t假设没问题.

在int循环中:( t_3从中分配k,它们是相同的类型)

if (__pyx_t_3 < 0) {
  __pyx_t_3 += __pyx_v_A.shape[0];
  if (unlikely(__pyx_t_3 < 0)) __pyx_t_4 = 0;
} else if (unlikely(__pyx_t_3 >= __pyx_v_A.shape[0])) __pyx_t_4 = 0;
Run Code Online (Sandbox Code Playgroud)

在size_t循环中:

if (unlikely(__pyx_t_3 >= (size_t)__pyx_v_A.shape[0])) __pyx_t_4 = 0;
Run Code Online (Sandbox Code Playgroud)

因此,不需要进行环绕测试,因为它size_t是无符号的,并且保证在索引内存中的项目时不会回滚.其余几乎是一样的.

更新:关于你的unsigned int结果 - 你的int和size_t的大小是多少?他们有什么不同的规模,导致变化?在我的例子中,uint和size_t的C代码是相同的.(因为size_t是无符号的,在此系统上特别是unsigned int)

  • 一旦你知道你在做什么,总是关闭边界检查和环绕...我不知道使用size_t会自动暗示. (2认同)

Mik*_*ler 5

在 64 位系统上似乎有两个原因:

\n\n
    \n
  1. 使用无符号整数进行循环:

    \n\n
    %%cython\n\ncimport numpy as cnp\nimport numpy as np\n\ndef sum_int_unsigned(cnp.int64_t[::1] A):\n    cdef unsigned long s = 0\n    cdef unsigned k\n    for k in xrange(A.shape[0]):\n        s += A[k]\n    return s\n
    Run Code Online (Sandbox Code Playgroud)
  2. \n
  3. 使用 along代替 aint:

    \n\n
    %%cython\n\ncimport numpy as cnp\nimport numpy as np\n\ndef sum_int_unsigned_long(cnp.int64_t[::1] A):\n    cdef unsigned long s = 0\n    cdef unsigned long k\n    for k in xrange(A.shape[0]):\n        s += A[k]\n    return s\n
    Run Code Online (Sandbox Code Playgroud)
  4. \n
\n\n

时间:

\n\n
%timeit sum_int(a)\n1000 loops, best of 3: 1.52 ms per loop\n\n%timeit sum_size_t(a)\n1000 loops, best of 3: 671 \xc2\xb5s per loop\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用unsigned使我们成功了一半:

\n\n
%timeit sum_int_unsigned(a) \n1000 loops, best of 3: 1.09 ms per loop\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用long其余的

\n\n
%timeit sum_int_unsigned_long(a)\n1000 loops, best of 3: 648 \xc2\xb5s per loop\n
Run Code Online (Sandbox Code Playgroud)\n