Как измерить длину последовательности генератора (составление списка против выражения генератора)

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

 seq_len = sum([1 for _ in euler14_seq(sv)])  # list comp

и

 seq_len = sum(1 for _ in euler14_seq(sv))    # generator expression

sv - постоянное начальное значение для последовательности.

Я ожидал, что понимание списка будет медленнее, а выражение генератора - быстрее, но оказалось, что все наоборот.

Я предполагаю, что первый будет намного более интенсивным с точки зрения памяти, поскольку он сначала создает полный список в памяти - отчасти я думал, что он будет медленнее.

Мой вопрос: можно ли обобщить это наблюдение? И это связано с тем, что во втором операторе задействованы два генератора, а не в первом?

Я просмотрел эти Какой самый короткий способ подсчитать количество элементов в генераторе / итераторе?, Длина вывода генератора и Есть ли какой-либо встроенный способ получить длину итерируемого в python? и видел некоторые другие подходы к измерению длины последовательности, но я специально любопытно сравнить составление списка с выражением генератора.

PS: Это возникло, когда я решил решить проект Эйлера № 14 на основе вопроса, заданного вчера на SO. .

(Кстати, каково общее мнение об использовании '_' в местах, где значения переменных не нужны).

Это было сделано с помощью Python 2.7.2 (32-разрядная версия) под 64-разрядной версией Windows 7.


person Levon    schedule 05.07.2012    source источник
comment
Использование '_' является нормой для нежелательных варов - это общепринятая и общепринятая практика - но, боюсь, с остальным я не могу вам помочь.   -  person Jon Clements♦    schedule 06.07.2012
comment
Есть еще немного работы по настройке генератора. Как только последовательность станет достаточно длинной, выражение генератора должно быть быстрее   -  person John La Rooy    schedule 06.07.2012
comment
А что насчет len(list(euler14_seq(sv)))? Кроме того, если вы тестируете производительность таким образом, вы должны сказать, на какой платформе вы тестируете. В частности, версия Python и ОС и, возможно, информация об оборудовании.   -  person Peter Graham    schedule 06.07.2012
comment
Я думаю, что вкратце генераторы вводят __call__ накладные расходы (которые могут быть медленными в Python), а listcomp - нет, но это внутреннее чувство, что я не могу резервировать ссылками ...   -  person Jon Clements♦    schedule 06.07.2012
comment
... а также то, что оператор listcomp более оптимизирован, поскольку выполняемый код статичен, а генератор может пузыриться и преследовать другие вещи по желанию   -  person Jon Clements♦    schedule 06.07.2012
comment
@PeterGraham Я добавил дополнительную информацию о версии / ОС Python в свой пост - спасибо за предложение. Я мог бы попробовать len() в обоих выражениях, но ожидал, что результат не изменится. Кроме того, применяя list() к генератору, разве вы не устраняете в основном сравнение генератора и списка?   -  person Levon    schedule 06.07.2012
comment
@Levon: Я предлагал другой способ определить длину генератора. Вероятно, это не имеет отношения к тому, быстрее ли понимание списка или выражение генератора. Разница в том, что если у вас есть список, len работает очень быстро и O (1), тогда как sum, вероятно, намного медленнее и O (n)   -  person Peter Graham    schedule 06.07.2012
comment
@PeterGraham Понятно .. спасибо.   -  person Levon    schedule 06.07.2012


Ответы (2)


На этом компьютере выражение генератора становится быстрее где-то между 100000 и 1000000.

$ python -m timeit "sum(1 for x in xrange(100000))"
10 loops, best of 3: 34.8 msec per loop
$ python -m timeit "sum([1 for x in xrange(100000)])"
10 loops, best of 3: 20.8 msec per loop
$ python -m timeit "sum(1 for x in xrange(1000000))"
10 loops, best of 3: 315 msec per loop
$ python -m timeit "sum([1 for x in xrange(1000000)])"
10 loops, best of 3: 469 msec per loop
person John La Rooy    schedule 05.07.2012
comment
Я увеличил значение sv до 1000000000, по-прежнему составление списка выполняется быстрее (25 мкс / цикл против 30 мкс / цикл). - person Levon; 06.07.2012
comment
@Levon, я думаю, что главный удар по LC - это выделение памяти. Ваш намного быстрее, чем мой. Для загруженного веб-сервера компромисс может оказаться сложным, поскольку хранение этих временных списков в вашей драгоценной оперативной памяти может быть дороже, чем дополнительные циклы, используемые генератором. - person John La Rooy; 06.07.2012
comment
Возможно, у меня действительно много оперативной памяти. И ваша точка зрения в комментариях по повторной настройке генератора тоже хорошая. Все еще немного озадачивает. Мне придется еще немного поиграть с этим. Спасибо. - person Levon; 06.07.2012

Следующий блок кода должен генерировать длину:

>>> gen1 = (x for x in range(10))
>>> len(list(gen1))
10
person Ashwini Chaudhary    schedule 05.07.2012
comment
Я не хотел путать len() с sum(), чтобы сравнение было верным. И основная суть моего вопроса - выяснить, всегда ли составление списков будет быстрее, чем выражения генератора в целом. - person Levon; 06.07.2012
comment
@Levon взгляните на это: stackoverflow.com/questions / 47789 / - person Ashwini Chaudhary; 06.07.2012
comment
Спасибо .. Я внимательно посмотрю на это (просто бегло просмотрел) - person Levon; 06.07.2012