Подтвердить что ты не робот

Что, как правило, быстрее, доходность или добавление?

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

Что обычно быстрее:

  • yield s, или
  • несколько append() внутри функции, затем return последующий list?

Я был бы рад узнать, в каких ситуациях yield будет быстрее, чем append() или наоборот.

4b9b3361

Ответ 1

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

# yield_vs_append.py
data = range(1000)

def yielding():
    def yielder():
        for d in data:
            yield d
    return list(yielder())

def appending():
    lst = []
    for d in data:
        lst.append(d)
    return lst

Это результат:

python2.7 -m timeit -s "from yield_vs_append import yielding,appending" "yielding()"
10000 loops, best of 3: 80.1 usec per loop

python2.7 -m timeit -s "from yield_vs_append import yielding,appending" "appending()"
10000 loops, best of 3: 130 usec per loop

По крайней мере, в этом очень простом тесте yield быстрее, чем append.

Ответ 2

Недавно я задал себе аналогичный вопрос, исследующий способы генерации всех перестановок списка (или кортежа) либо путем добавления в список, либо через генератор, и нашел (для перестановок длины 9, которые занимают около секунды или около того для генерации):

  • Наивный подход (перестановки - это списки, добавление к списку, список возврата списков) занимает примерно в три раза больше времени itertools.permutations
  • Использование генератора (т.е. yield) уменьшает это на ок. 20%
  • Использование генератора и генерации наборов является самым быстрым, примерно в два раза больше времени itertools.permutations.

Возьми с солью соль! Сроки и профилирование были очень полезными:

if __name__ == '__main__':
    import cProfile
    cProfile.run("main()")

Ответ 3

Существует еще более быстрая альтернатива TH4Ck yielding(). Это понимание списка.

In [245]: def list_comp():
   .....:     return [d for d in data]
   .....:

In [246]: timeit yielding()
10000 loops, best of 3: 89 us per loop

In [247]: timeit list_comp()
10000 loops, best of 3: 63.4 us per loop

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

Ответ 4

В первую очередь u должен решить, если вам нужен генератор, это также улучшило метод. Как генератор списков "[elem для elem in somethink]". И генераторы должны быть рекомендованы, если вы просто используете значение в списке для некоторых операций. Но если вам нужен список для многих изменений и работать со многими элементами одновременно, это должен быть список. (Как и 70%, если использовать стандартный список программистов, лучше будет генератор. Используйте меньше памяти, просто многие люди просто не видят другого способа списка. К сожалению, в нашу эпоху многие люди моют хорошую оптимуляцию и делают только работу.)

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

Выход быстрее, чем возврат, и я докажу это. Просто проверьте этих ребят:

data = range(1000)

def yielder():
    yield from data

def appending():
    L = []
    app = list.append
    for i in data:
        app(L, i)
    return L

def list_gen():
    return [i for i in data]

Конечно, добавление будет медленнее, чем другие идеи, потому что мы создаем и расширяем список любого времени цикла. Просто цикл "for" очень неоптимизирован, если вы можете избежать этого, сделайте это. Becouse на любом этапе эта функция загружает следующий элемент и записывает нашу переменную, чтобы получить это значение объекта в памяти. Таким образом, мы переходим к любому элементу, создаем ссылку, расширяем список в цикле (объявленный метод является огромным оптическим регулятором скорости), когда мы генерируем только возврат, итоговое количество получило 2000 элементов в двух списках.

list_gen меньше по памяти, мы просто возвращаем элементы, но, как и вверх, мы генерируем список secound. Теперь у нас есть два списка, оригинальные данные и ее копия. Итоговые данные за 2000 элементов. Там мы просто избегаем шага с созданием ссылки на переменную. Becouse наш ген в списках избегает этого шага. Просто напишите элементы.

yielder использует меньше всего памяти, потому что мы только что получили значение из данных. Мы избегаем одной ссылки. Например:

data = range(1000)

def yielder():
    yield from data

def list_gen():
    return [i for i in data]

#Now we generate next reference after line [i for i in data]
for i in list_gen():
    #some instruction

#This is our first reference, becouse was yield from data.
for i in yielder():
    #some instruction

Используйте только один элемент для какой-либо команды, а не все из списка, следующее одно значение yielder вернется в следующий цикл, а не журнал всех 1000 элементов для записи в ссылке.

Счастье для небольшой частичной отрывки, просто, когда я случайно попал в крест от поиска в Google, другие программисты-программисты на пионерах могут увидеть эту чушь.