一些性能测量,使用timeit
,而不是try 手动使用time
.
首先,Apple 2.7.2 64位:
In [37]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.05 s per loop
现在,python.org 3.3.0 64位:
In [83]: %timeit collections.deque((x for x in range(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.32 s per loop
In [84]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.31 s per loop
In [85]: %timeit collections.deque((x for x in iter(range(10000000)) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.33 s per loop
显然是3.Xrange
确实比2慢一点.xxrange
.OP的xrange
函数与此无关.(这并不奇怪,因为对__iter__
插槽的一次性调用不太可能在对循环中发生的任何事情的range
00000次调用中可见,但有人提出了这种可能性.)
但它只慢了30%.行动怎么会慢2倍呢?如果我用32位Python重复相同的测试,我会得到1.58对3.12.所以我的猜测是,这是3.x以损害32位的方式针对64位性能进行优化的又一种情况.
但这真的重要吗?看看这个,再次使用3.3.0 64位:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
因此,构建list
所需的时间是整个迭代的两倍多.
至于"比Python2.6+消耗更多的资源",从我的测试来看,它看起来像一个3.Xrange
的尺寸和2的尺寸完全一样.xxrange
,而且,即使它是10倍大,构建不必要的列表仍然是一个比范围迭代可能做的任何事情都多出大约range
0000000倍的问题.
那么用显式for
循环代替deque
中的C循环呢?
In [87]: def consume(x):
....: for i in x:
....: pass
In [88]: %timeit consume(x for x in range(10000000) if x%4 == 0)
1 loops, best of 3: 1.85 s per loop
因此,在for
语句中浪费的时间几乎与在迭代range
语句的实际工作中浪费的时间一样多.
如果你担心优化范围对象的迭代,你可能找错了地方.
与此同时,你一直在问为什么xrange
被移除了,不管人们多少次告诉你同样的事情,但我再重复一遍:它没有被移除:它被重新命名为range
,2.x range
就是被移除的.
这里有一些证据证明3.3 range
对象是2的直系后代.xxrange
对象(而不是2.xrange
函数):3.3 range
和2.7 xrange
的源.您甚至可以看到change history(我相信,它链接到了替换文件中任意位置字符串"xrange"的最后一个实例的更改).
那么,为什么要慢一点呢?
首先,他们增加了很多新功能.另一方面,他们在各地做了各种各样的改变(尤其是在迭代过程中),这些改变的副作用很小.而且已经有很多工作在戏剧性地优化各种重要 case ,即使有时它会稍微悲观一些不太重要的 case .把这些加起来,我并不惊讶尽可能快地迭代range
现在会慢一点.这是那些不太重要的案件之一,没有人会足够关注.在现实生活中,没有人可能会遇到这样的用例:这种性能差异是他们代码中的热点.