进行一些性能评估,timeit
而不是尝试使用手动进行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.x慢一些xrange
。OP的xrange
功能与此无关。(不足为奇,因为__iter__
在循环中发生的任何事情的1000万次调用中,对插槽的一次性调用不太可能看到,但有人提出来了。)
但这仅慢了30%。OP如何使速度慢2倍?好吧,如果我对32位Python重复相同的测试,则得出的结果是1.58和3.12。因此,我的猜测是,这是3.x针对64位性能进行了优化(以损害32位的方式)的又一案例。
但这真的重要吗?再次使用64位3.3.0进行检查:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
因此,构建所需的list
时间是整个迭代的两倍以上。
至于“比Python 2.6+消耗更多的资源”,在我的测试中,看起来3.xrange
的大小与2.x的大小完全相同xrange
,即使它的大小是10x的大小,也可以构建不必要的列表问题仍然比范围迭代可能做的任何事情多出10000000x。
那么显式for
循环而不是内部的C循环deque
呢?
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.xrange
是被删除的。
这是3.3range
对象是2.xxrange
对象(而不是2.xrange
函数)的直接后代的证明:3.3range
和2.7xrange
的源。您甚至可以查看更改历史记录(我相信,该更改已链接到替换文件中任何位置的字符串“ xrange”的最后一个实例的更改)。
那么,为什么它变慢?
好吧,其中之一是,他们添加了许多新功能。另一方面,他们已经在整个地方(尤其是在迭代过程中)进行了各种具有较小副作用的更改。尽管有时有时会稍微低估不太重要的案例,但仍进行了大量工作来显着优化各种重要案例。将所有这些加起来,range
对于尽快进行迭代现在变得慢一点,我并不感到惊讶。这是最重要的案例之一,没有人会足够关注。没有人会遇到现实生活中的用例,这种性能差异是他们代码中的热点。