Преимущества производительности для итераторов? - PullRequest
18 голосов
/ 10 марта 2009

Какие (если есть) преимущества в производительности предлагаются с помощью итераторов. Это похоже на «Правильный путь» для решения многих проблем, но создает ли он более быстрый / более сознательный код? Я думаю конкретно на Python, но не ограничиваю ответы только этим.

Ответы [ 9 ]

20 голосов
/ 10 марта 2009

На самом деле в списке рассылки python есть очень хорошая почта: Итераторы против Списков . Это немного датировано (с 2003 года), но, насколько я знаю, оно все еще действует.

Вот резюме:

Для небольших наборов данных подходы на основе итераторов и списков имеют схожие спектакль. Для больших наборов данных итераторы экономят время и пространство.

Что я мог бы извлечь из этого, так это: итераторы должны быть предпочтительнее, чем загрузка данных в список, если это возможно. Но если у вас нет большого набора данных, не искажайте ваш код, чтобы создать что-то, что должно поместиться в списке для работы с итератором.

12 голосов
/ 10 марта 2009

Для Python генераторы будут работать быстрее и эффективнее использовать память. Просто подумайте о примере range(1000) против xrange(1000) (это было изменено в 3.0, диапазон теперь является генератором). С помощью Range вы предварительно строите свой список, но XRange просто имеет объект-генератор и при необходимости выдает следующий элемент.

Разница в производительности невелика для мелких вещей, но как только вы начнете проверять их, получая все больший и больший набор информации, вы заметите это довольно быстро. Кроме того, не только для того, чтобы сгенерировать и затем выполнить шаг, вы будете потреблять дополнительную память для своего предварительно созданного элемента, где-как с помощью выражения генератора получается только 1 элемент за раз.

7 голосов
/ 10 марта 2009

Основное преимущество итераторов не в производительности. По моему опыту, наиболее эффективным решением является создание алгоритма, который встраивает выбранную вами структуру данных. Преимущество итераторов заключается в том, что они позволяют разделить данные и алгоритм и, следовательно, обобщить и повторно использовать оба. Если это также можно сделать без (или с небольшим) снижения производительности, то это чистый выигрыш.

Мой любимый пример использования итератора можно найти в C ++ Стандартная библиотека шаблонов . Ему удается продемонстрировать мощь и красоту абстракции, четко разделив контейнер и алгоритм, не жертвуя при этом производительностью. Понимание этого дизайна оказало глубокое влияние на то, как я думаю о коде.

3 голосов
/ 10 марта 2009

Для резервного копирования @ ответа Кристиана Виттса :

range против xrange производительность

python25 -mtimeit "for i in xrange(1000): pass"
10000 loops, best of 3: 56.3 usec per loop

python25 -mtimeit "for i in range(1000): pass"
10000 loops, best of 3: 80.9 usec per loop

python26 -mtimeit "for i in xrange(1000): pass"
10000 loops, best of 3: 48.8 usec per loop

python26 -mtimeit "for i in range(1000): pass"
10000 loops, best of 3: 68.6 usec per loop

Кстати, ни range(), ни xrange() не являются итераторами:

>>> hasattr(range(1), 'next')
False
>>> hasattr(xrange(1), 'next')
False
>>> iter(xrange(1))
<rangeiterator object at 0x0097A500>
>>> iter(range(1))
<listiterator object at 0x00A7BFD0>
>>> iter([])
<listiterator object at 0x00A7BE30>
>>> iter(i for i in (1,))
<generator object at 0x00A7F940>
>>> (i for i in (1,))
<generator object at 0x00A7FDC8>
2 голосов
/ 09 апреля 2009

Мой вывод из многих приведенных выше ответов звучит так: «Использовать список для кодирования. При необходимости перефакторинг с использованием итераторов» Разница не очевидна, если у вас большой набор данных.

Следует также отметить, что даже при частом использовании списков набор данных, с которым мы работаем, становится все меньше и меньше.

2 голосов
/ 10 марта 2009

Итераторы - это просто классы, которые реализуют определенный интерфейс , в частности интерфейс для , переходящий к следующему . В Python списки, кортежи, слова, строки и файлы реализуют этот интерфейс. Если они плохо реализованы, это может привести к снижению производительности, но интерфейсу нет ничего, что могло бы указывать на хорошую или плохую производительность.

1 голос
/ 10 марта 2009

Итератор - это просто объект, предоставляющий методы, позволяющие обходить коллекцию. Вы можете пройти через все элементы массива или все узлы дерева с одинаковым интерфейсом. Деревья и массивы - это очень разные структуры данных, и для их обхода требуются разные методы ... но с помощью итератора вы можете проходить по всем элементам одинаково.

Для одного типа коллекции также могут быть разные способы его обхода, и в одной коллекции может быть несколько итераторов. Вы можете использовать итератор с глубиной или итератор с шириной, проходящий по древовидной структуре и возвращающий узлы. в разных порядках. Итераторы не предназначены для повышения производительности ... но обычно для обеспечения согласованного интерфейса для обхода структур.

0 голосов
/ 21 ноября 2017

Немного не по теме, но придает больший вес использованию списков над итераторами в целом: с итераторами легче получить побочные эффекты, учтите это:

def foo(arg: Iterable[str]):
  print(list(arg)) # side effect: arg is exhausted at this point
  ...

Вы можете сказать, что тестирование должно поймать это, но иногда это не так. Списки не имеют этой проблемы, так как они не сохраняют состояния (в смысле итерации).

0 голосов
/ 04 ноября 2016

Есть один ответ, который, я думаю, немного смущает концепцию генератора и итератора. Поэтому я решил попробовать ответить на этот вопрос на примере метафоры.

Я работаю на кухне, мой босс поручил мне сложить 10 (или 100, или миллион) хлебов. У меня есть шкала и калькулятор (фокусы моего алгоритма). Ниже приведен итеративный объект, генератор, итератор, разность подходов:

  1. Итерируемый объект: Каждый хлеб хранится в одной коробке (памяти), я взвешиваю первый (или 0-й) хлеб, кладу его вес и кладу хлеб обратно в коробку, затем иду к следующей, взвешиваю и кладу обратно, и так далее, и т. д. и т. д. В конце концов, я получил общий вес, и 10 (100 или миллион) хлебов все еще находятся в их коробках.

  2. Генератор: Ящиков для хранения всего этого хлеба недостаточно, поэтому я попросил помощи у пекаря (генератора), он делает первый хлеб, дает его мне, я взвешиваю, кладу результат, выбрасываю этот хлеб и попросите у него еще один, и так далее, и так далее, пока я не получу последний хлеб (или, возможно, у пекаря не хватает муки). В итоге у меня результат, ни одного хлеба там нет. Но кого это волнует, мой босс только просит, чтобы я взвесил этот хлеб, он не сказал, что я не могу выбросить его (какой замечательный автобусный мастер).

  3. Итератор: Я прошу кого-то (итератор) помочь мне перенести первый хлеб на весы, я его взвешиваю, кладу результат вниз. Этот кто-то может взять следующий для измерения, и так далее, и т. Д. Я на самом деле понятия не имею, если кто-то (итератор) получит хлеб из коробки или от пекаря. В конце концов, я получил общий вес, для меня это не имеет значения.

В любом случае, подведем итог:

  1. Итерируемому объекту требуется некоторое количество памяти для хранения данных для начала. В конце концов, данные все еще там.

  2. Генератору не потребуется память для хранения данных, для начала он генерирует данные на ходу.

  3. Итератор - это канал между алгоритмом и его данными. Эти данные могут быть уже там и сохранены в памяти или могут быть сгенерированы на ходу генератором. В первом случае эта память будет освобождаться побитно, поскольку итератор продолжает итерацию. Поэтому я очень согласен с приведенным выше ответом, что итератор хорош из-за своей абстракции, которая позволяет изолировать алгоритм и данные.

Python не совсем так работает. Надеюсь, это поможет уточнить немного.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...