[英]Cython: why is size_t faster than int?
Changing certain Cython variables from type int
to type size_t
can significantly reduce some functions times (~30%), but I do not understand why. 从类型更改某些变量用Cython
int
输入size_t
可以显著减少一些功能倍(〜30%),但我不明白为什么。
For example: 例如:
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))
And the timing results: 时间结果如下:
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
I am new to Cython, and know Fortran better than C. Help me out. 我是Cython的新手,比C.更了解Fortran。帮帮我。 What is the important difference between these two variable types that causes such a performance difference?
这两种变量类型之间的重要区别是什么导致了这种性能差异? What is it that I don't grok about Cython?
什么是我不喜欢Cython?
You'd likely have to do a line by line profiling to find out exactly, but one thing stands out to me from the produced C file: int
version is checked for wraparound to negative numbers, size_t
is assumed ok. 您可能不得不进行逐行分析以找出确切的结果,但有一件事从我生成的C文件中脱颖而出:检查
int
版本是否为环绕负数, size_t
假定为ok。
In the int loop: ( t_3
is assigned from k
, they're the same type) 在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;
In the size_t loop: 在size_t循环中:
if (unlikely(__pyx_t_3 >= (size_t)__pyx_v_A.shape[0])) __pyx_t_4 = 0;
So no wraparound test is needed because size_t
is unsigned and guaranteed not to wrap around when indexing items in memory. 因此,不需要进行环绕测试,因为
size_t
是无符号的,并且保证在索引内存中的项目时不会size_t
。 The rest is virtually the same. 其余几乎是一样的。
Update: regarding your unsigned int
results - what's your size of int and size_t? 更新:关于你的
unsigned int
结果 - 你的int和size_t的大小是多少? Any chance they're different size, causing the change? 他们有什么不同的规模,导致变化? In my case the C code for uint and size_t is identical.
在我的例子中,uint和size_t的C代码是相同的。 (since size_t is unsigned and specifically unsigned int on this system)
(因为size_t是无符号的,在此系统上特别是unsigned int)
On a 64 bit system there seem to be two reasons: 在64位系统上,似乎有两个原因:
Use an unsigned integer for the loop: 对循环使用无符号整数:
%%cython cimport numpy as cnp import numpy as np def sum_int_unsigned(cnp.int64_t[::1] A): cdef unsigned long s = 0 cdef unsigned k for k in xrange(A.shape[0]): s += A[k] return s
Use a long
instead of an int
: 使用
long
而不是int
:
%%cython cimport numpy as cnp import numpy as np def sum_int_unsigned_long(cnp.int64_t[::1] A): cdef unsigned long s = 0 cdef unsigned long k for k in xrange(A.shape[0]): s += A[k] return s
Timings: 时序:
%timeit sum_int(a)
1000 loops, best of 3: 1.52 ms per loop
%timeit sum_size_t(a)
1000 loops, best of 3: 671 µs per loop
Using unsigned
brings us half way: 使用
unsigned
将我们带到了一半:
%timeit sum_int_unsigned(a)
1000 loops, best of 3: 1.09 ms per loop
Using long
accounts for the rest: 使用
long
帐户来完成剩下的工作:
%timeit sum_int_unsigned_long(a)
1000 loops, best of 3: 648 µs per loop
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.