2010-01-31 4 views
7

Я пытался найти самый быстрый способ подсчета количества элементов в списке, соответствующем определенному фильтру. В этом случае, найдя количество нечетных чисел в списке.Почему этот генкс хуже, чем понимание списка?

При этом, я был удивлен результатами сравнения список понимание против эквивалентного выражения генератора:

python -m timeit -s "L = xrange(1000000)" "sum([1 for i in L if i & 1])" 
10 loops, best of 3: 109 msec per loop 

python -m timeit -s "L = xrange(1000000)" "sum(1 for i in L if i & 1)" 
10 loops, best of 3: 125 msec per loop 

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

Что такое генкс, что делает его медленнее по сравнению с listcomp, который создает новый список с 1 миллионом элементов ...?

(Кстати, самый быстрый способ я нашел: x = 1; len(filter(x.__and__, L)) И да, я знаю, писать код, как убивает котенок, я делаю это для удовольствия.)

ответ

15

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

Будет ли более быстрый подход к подходу или генераторному подходу будет в реальной программе зависит от конкретной ситуации с памятью, включая фрагментацию, что невозможно точно воспроизвести в «микро-контроле». IOW, в конце концов, если вы действительно заботитесь о производительности, вы должны тщательно сравнить (и, отдельно, профиль) свою фактическую программу (ы), а не только «игрушечные» микро-тесты, в общем случае.

+0

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

3

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

обновление: После тестирования, он сделал обратный

~% python -m timeit -s "L = xrange(1000000);oint=type('intEx', (int,),{})" "sum([oint(1) for i in L if i & 1])" 
10 loops, best of 3: 414 msec per loop 

~% python -m timeit -s "L = xrange(1000000);oint=type('intEx', (int,),{})" "sum(oint(1) for i in L if i & 1)" 
10 loops, best of 3: 392 msec per loop 

 Смежные вопросы

  • Нет связанных вопросов^_^