Почему этот Genexp выполняет хуже, чем понимание списка?

StackOverflow https://stackoverflow.com/questions/2173845

Вопрос

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

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

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 будучи обычным списком, а разные размеры, но во всех случаях выигрывает понимание списка.

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

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

Это было полезно?

Решение

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

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

Другие советы

От того, что я помню, для каждого результата необходимо активировать рамку генератора, тогда как понимание списка использует одну раму активации. Инкрементная стоимость в списке сжатие является дополнительной стоимостью памяти - ссылки на 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top