Некоторые измерения производительности, используя 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-bit:
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.x range
действительно немного медленнее , чем 2.x xrange
. И xrange
функция ОП не имеет к этому никакого отношения. (Не удивительно, поскольку одноразовый вызов в __iter__
слот вряд ли будет виден среди 10000000 вызовов, что бы ни происходило в цикле, но кто-то поднял это как возможность.)
Но это только на 30% медленнее. Как ОП получил 2x как медленный? Что ж, если я повторю те же тесты с 32-битным Python, я получу 1,58 против 3,12. Поэтому я предполагаю, что это еще один из тех случаев, когда 3.x был оптимизирован для 64-битной производительности таким образом, что это наносит ущерб 32-битной системе.
Но действительно ли это имеет значение? Проверьте это, с 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
занимает более чем вдвое больше времени, чем вся итерация.
А что касается «потребляет гораздо больше ресурсов, чем Python 2.6+», то из моих тестов похоже, что 3.x range
точно такого же размера, что и 2.x xrange
- и, даже если он в 10 раз больше, создает ненужный список все еще на 10000000 раз больше проблем, чем любая другая итерация диапазона.
А как насчет явного 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.x range
- это то, что было удалено.
Вот некоторые доказательства того, что range
объект 3.3 является прямым потомком xrange
объекта 2.x (а не range
функции 2.x ): источник 3.3range
и 2.7xrange
. Вы даже можете увидеть историю изменений (я думаю, что она связана с изменением, которое заменило последний экземпляр строки «xrange» в любом месте файла).
Итак, почему это медленнее?
Ну, например, они добавили много новых функций. С другой стороны, они сделали все виды изменений повсеместно (особенно внутри итерации), которые имеют незначительные побочные эффекты. И было проделано много работы, чтобы значительно оптимизировать различные важные случаи, даже если иногда они слегка пессимизируют менее важные случаи. Добавьте все это, и я не удивлен, что итерация range
как можно быстрее теперь немного медленнее. Это один из тех менее важных случаев, на которых никто никогда не будет обращать внимания. Ни у кого, вероятно, никогда не будет реального сценария использования, где эта разница в производительности является горячей точкой в их коде.
range
в Python 3.x взятxrange
из Python 2.x. Это был фактически Python 2.x,range
который был удален.