Почему передача списка в качестве параметра работает лучше, чем передача генератора? - PullRequest
3 голосов
/ 31 января 2020

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

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

Мой ответ был в основном такой функцией:

def how_many_different_lists(lists):
    s = set(str(list_) for list_ in lists)
    return len(s)

Теперь ситуация возникла, когда я измерил время выполняется, и я сравнил его с практически той же функцией, но передавая список вместо генератора в качестве параметра для set ():

def the_other_function(lists):
    s = set([str(list_) for list_ in lists])
    return len(s)

Это декоратор, который я использую для тестирования функций:

import time

def timer(func):
    def func_decorated(*args):
        start_time = time.clock()
        result = func(*args)   
        print(time.clock() - start_time, "seconds")
        return result
    return func_decorated

И это были результаты для данного ввода:

>>> list1 = [[1,2,3],[1,2,3],[1,2,2],[1,2,2]]
>>> how_many_different_lists(list1)
6.916326725558974e-05 seconds
2
>>> the_other_function(list1)
3.882067261429256e-05 seconds
2

Даже для больших списков:

# (52 elements)
>>> list2= [[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2],[1,2,3],[1,2,3],[1,2,2],[1,2,2]]
>>> how_many_different_lists(list2)
0.00023560132331112982 seconds
2
>>> the_other_function(list2)
0.00021329059177332965 seconds
2

Теперь мой вопрос: Почему второй пример быстрее первого? Разве генераторы не должны быть быстрее из-за того, что производят элементы «по требованию»? Раньше я думал, что составление списка и его повторение выполняются медленнее.

PS: я много раз тестировал, получая в основном те же результаты.

1 Ответ

1 голос
/ 22 февраля 2020

Я проверял ваши функции:

enter image description here

from simple_benchmark import BenchmarkBuilder
from random import choice

b = BenchmarkBuilder()
from operator import setitem


@b.add_function()
def how_many_different_lists(lists):
    s = set(str(list_) for list_ in lists)
    return len(s)


@b.add_function()
def the_other_function(lists):
    s = set([str(list_) for list_ in lists])
    return len(s)


@b.add_arguments('Number of lists in the list')
def argument_provider():
    for exp in range(2, 18):
        size = 2**exp

        yield size,  [list(range(choice(range(100)))) for _ in range(size)]


r = b.run()
r.plot()

Генераторы ленивы, потому что выражение генератора будет создавать элементы на лету по сравнению с понимание списка, которое создаст весь список в памяти. Вы можете прочитать больше здесь: Выражения генератора и понимание списка

Как видно из теста, между ними нет такой большой разницы.

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