Накладные расходы на рекурсию — насколько это серьезно?[дубликат]

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

Вопрос

Возможный дубликат:
Является ли рекурсия быстрее, чем цикл?

Впервые меня серьезно научили программировать на C около 15 лет назад.Моему работодателю нужен был высокооптимизированный код для сложных в вычислительном отношении задач.Я помню, что мне не раз советовали переписывать рекурсии в виде циклов, даже в ущерб читабельности, чтобы избежать «накладных расходов на рекурсию». Как я тогда понял, накладные расходы на рекурсию — это дополнительные усилия, необходимые для того, чтобы поместить данные в стек и затем извлечь их из него.

Сейчас я пишу на C, Python, Perl, а иногда и на Java, и иногда задаюсь вопросом о рекурсиях.Можно ли еще что-то получить, переписав их?Что, если это хвостовая рекурсия?Сделали ли современные компиляторы все эти вопросы спорными?Неактуальны ли подобные опасения для интерпретируемых языков?

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

Решение

Рекурсия может привести к значительным накладным расходам, если ядро ​​рекурсивной функции требует меньше вычислительных затрат, чем код входа/выхода функции и стоимость самого вызова.Лучший способ это выяснить — просто профилировать две версии кода — одну рекурсивную и одну нет.

Тем не менее, если ваша идея избежать рекурсии состоит в том, чтобы самостоятельно создать структуру, подобную стеку, будьте осторожны — это не обязательно может быть быстрее, чем более простой рекурсивный подход.Опять же, профилирование — ваш друг.

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

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

Это серьезно. Большинство языков, которые я в курсе, имеющую реальные затраты на функциональные вызовы (компиляторы для них могут, как правило, могут сделать рекурсию хвоста, поэтому иногда это не проблема).

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

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

def sum1through (n):
    if n == 0 return 0
    return n + sum1through (n-1)

так как это делать для n из двадцати миллионов не было бы здоровым для стека.

Вопрос все еще существует. Рекурсия принимает много места для стека, поскольку каждый раз, когда способ вызовет сам метод, указатель к нему, и его локальные переменные снова генерируются. Количество функционируемых вызовов, выполненных во время рекурсии, делает использование памяти O (N); по сравнению с o (1) нерекурсивной функции, такой как петли.

Я не думаю, что ни один из языков, которые вы упомянули требовать что платформа / компилятор реализует Устранение вызова хвоста. Отказ Вы можете найти языки, которые делать Требуется эта оптимизация - большинство функциональных языков имеют это требование.

Однако еще одна вещь, которую вы должны рассмотреть, так это то, что компьютеры стали заказами величин быстрее, чем было 15 лет назад, поэтому сейчас гораздо реже, тогда до этого вам нужно беспокоиться о микрооптизациях. Программа, которую 15 лет назад может потребоваться осторожной оптимизации рук в ассемблере, чтобы получить достойную производительность, может быстро быстро работать на современном компьютере, даже если написано на языке более высокого уровня, такими как Java. Это не значит, что производительность никогда больше не проблема - но вы должны сосредоточиться на выборе Правильный алгоритм и на написании удобочитаемый код. Только делают микро-оптимизацию после того, как вы измеряли производительность, и вы можете увидеть, что рассматриваемый код - это узкое место.

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

Люди говорят много глупых вещей о производительности.

  1. если ты нужно Рекурсия, как правило, прогуляться по глубине, то вам это нужно, поэтому используйте его.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top