C -如何在python中处理CPU缓存(或调用函数一次的最快方式)



我发现python的VM似乎对CPU-Cache非常不友好。

例如:

import time
a = range(500)
sum(a)
for i in range(1000000): #just to create a time interval, seems this disturb cpu cache?
    pass

st = time.time()
sum(a)
print (time.time() - st)*1e6

:

> 100us

的另一个例子:

import time
a = range(500)
for i in range(100000):
    st = time.time()
    sum(a)
    print (time.time() - st)*1e6

:

~ 20us

我们可以看到,当频繁运行时,代码变得快得多。

有解决方案吗?

我们可以参考这个问题:(应该是同一个问题)Python函数(或代码块)在循环

中设置一个时间间隔,运行速度会慢得多。我觉得这个问题很难。必须对python虚拟机、c语言和cpu缓存的原理有深入的了解。

你有什么建议关于在哪里张贴这个问题可能的答案?

你的假设"我们可以看到当频繁运行时,代码变得更快"是不太正确的。

这个循环

#just to create a time interval, seems this disturb cpu cache?
for i in range(1000000): 
    pass

不仅仅是一个简单的时间延迟。在Python 2中,它创建了一个包含1,000,000个整数对象的列表,循环遍历它,然后销毁它。在Python 3中,range()是一个生成器,所以它对内存的浪费要少得多;Python 2对应的是xrange()

在标准CPython实现中,列表是指向其所包含对象的指针数组。在32位系统中,整数对象占用12个字节,空列表对象占用32个字节,当然指针占用4个字节。所以range(1000000)总共消耗32 + 1000000 *(4 + 12)= 16000032字节。

一旦循环结束,range()列表上的引用计数降为零,因此它及其内容有资格进行垃圾收集。垃圾收集一百万个整数需要花费一点时间,所以在循环结束后注意到时间延迟并不奇怪。此外,创建&释放所有这些对象通常会导致一些内存碎片,这将影响后续代码的效率。

FWIW,在我的2GHz Pentium 4 Linux系统上,您的第一个代码块在38 - 41µs范围内打印值,但如果我将环路更改为使用xrange(),则时间下降到31 - 34µs。

如果代码被修改为在计算sum(a)之前防止range()的垃圾收集,那么我们使用range()还是xrange()在计时上没有什么区别。

import time
a = range(500)
sum(a)
bigrange = xrange(1000000)
for i in bigrange:
    pass
st = time.time()
sum(a)
print (time.time() - st) * 1e6
#Maintain a reference to bigrange to prevent it 
#being garbage collected earlier
print sum(bigrange)

最新更新