Являются ли генераторы Python быстрее, чем вложенные циклы for?

У меня возникли некоторые проблемы, пытаясь понять генераторы.

Различается ли время выполнения этих функций при выполнении одной и той же задачи?

def slow_sum(size):
    x= 0
    for i in range(size):
        for j in range(size):
            x += i + j
    return x

def fast_sum(size):
    return sum( [ (i+j) for j in range(size) for i in range(size)] )

size = 2000
slow_val = slow_sum(size)
fast_val = fast_sum(size)
assert slow_val == fast_val, "Values are not equal"

При профилировании обеих функций на моем компьютере с помощью cProfile я получил такой результат, но я ожидал, что они будут похожими.

Общее время

  • медленная_сумма (2000)

    • 0.85 ms
  • быстрая_сумма (2000)

    • 0.05 ms

Исходный файл: https://pastebin.com/fDfaSqyZ

Мой вывод: https://pastebin.com/wyy3v3iy


person SeoFernando    schedule 26.01.2019    source источник
comment
Это не генератор, это понимание списка. С генератором это будет sum((i+j) for j in range(size) for i in range(size))   -  person iz_    schedule 27.01.2019
comment
Не обманывайтесь. Это не быстрее. Посмотрите на этот обратный вопрос: медленнее, чем для цикла"> stackoverflow.com/questions/27905965/   -  person smac89    schedule 27.01.2019
comment
@ Tomothy32, генераторы, как правило, не быстрее, чем сначала создать список. Например, см. str.join; попробуйте это с генератором против списка и сравните результаты   -  person smac89    schedule 27.01.2019
comment
это специально для str.join, потому что ему все равно нужен список, а если его нет, он его создает. Не в случае sum   -  person Jean-François Fabre    schedule 27.01.2019
comment
slow_sum должен выполнять отдельные операции добавления Python; fast_sum суммирует список в C.   -  person chepner    schedule 27.01.2019
comment
slow_sum быстрее в моей системе :) оба вычисляются примерно за 0,5 секунды. Я начинаю сомневаться в вашем эталоне   -  person Jean-François Fabre    schedule 27.01.2019
comment
У меня почти такая же скорость: size = 1000, 10 раз с timeit: fast 1.25320039 - slow 1.1005855780000002   -  person iGian    schedule 27.01.2019
comment
Это наводящий вопрос, потому что теперь нам нужно согласовать, верно ли утверждение, что генераторы работают быстрее, чем циклы for; тогда мы должны придумать объяснение, почему. Но что, если вы ошибаетесь? И, как указывалось в большинстве комментариев, ваше первоначальное утверждение на самом деле неверно; также это не выражение генератора. Вопрос, который вы должны задать, заключается в том, почему в ЭТОМ случае; выражение генератора было быстрее, чем цикл for.   -  person smac89    schedule 27.01.2019
comment
Вы уверены, что смотрите на правильную часть вывода профилировщика? Вы должны смотреть на cumtime или столбец percall справа от cumtime. tottime игнорирует время, проведенное в sum или во фрейме стека понимания списка.   -  person user2357112 supports Monica    schedule 27.01.2019
comment
Ладно, да, ты смотришь на тоталтайм.   -  person user2357112 supports Monica    schedule 27.01.2019
comment
О, ладно, мой плохой :/ @user2357112   -  person SeoFernando    schedule 27.01.2019
comment
Генераторы экономят место. Пространство иногда важнее временной сложности с точки зрения фактических ресурсов и, следовательно, реального времени. Я обращаюсь к гипотетическому и игнорирую детали.   -  person Kenny Ostrom    schedule 27.01.2019


Ответы (1)


Вы смотрите не на тот столбец вывода профилировщика. tottime не учитывает все время, которое fast_sum проводит внутри вызова sum или кадра стека понимания списка. Вы должны смотреть на cumtime, который почти равен для двух функций.

person user2357112 supports Monica    schedule 26.01.2019