Как упоминалось в других ответах, CLR поддерживает оптимизацию хвостового вызова, и, похоже, исторически происходили прогрессивные улучшения. Но поддержка его на C # имеет открытую Proposal проблему в репозитории git для разработки языка программирования C # Поддержка хвостовой рекурсии № 2544.
Здесь вы можете найти полезные подробности и информацию. Например, @jaykrell упомянул
Позвольте мне поделиться тем, что я знаю.
Иногда обратный вызов - беспроигрышный результат. Это может сэкономить CPU. jmp дешевле, чем call / ret. Он может сэкономить стек. Прикосновение к меньшему количеству стопки обеспечивает лучшую локацию.
Иногда обратный вызов - это потеря производительности, выигрыш стека. В CLR есть сложный механизм, в котором вызываемой стороне передается больше параметров, чем получено вызывающей стороной. Я имею в виду, в частности, больше места в стеке для параметров. Это медленно. Но это сохраняет стек. Он будет делать это только с хвостом. префикс.
Если параметры вызывающего объекта больше, чем параметры вызываемого объекта, это обычно довольно простое беспроигрышное преобразование. Могут быть факторы, такие как изменение позиции параметра с управляемого на целое число / число с плавающей запятой, создание точных карт StackMaps и т. Д.
Теперь есть еще один аспект - алгоритмы, которые требуют устранения хвостовых вызовов, чтобы иметь возможность обрабатывать произвольно большие данные с фиксированным / малым стеком. Дело не в производительности, а в способности бегать вообще.
Также позвольте мне упомянуть (в качестве дополнительной информации), когда мы генерируем скомпилированную лямбду с использованием классов выражений в пространстве имен System.Linq.Expressions, есть аргумент с именем 'tailCall', который, как объяснено в его комментарии,
Логическое значение, указывающее, будет ли применяться оптимизация хвостового вызова при компиляции созданного выражения.
Я еще не пробовал это, и я не уверен, как это может помочь в связи с вашим вопросом, но, вероятно, кто-то может попробовать это и может быть полезно в некоторых сценариях:
var myFuncExpression = System.Linq.Expressions.Expression.Lambda<Func< … >>(body: … , tailCall: true, parameters: … );
var myFunc = myFuncExpression.Compile();
person
lifestyle
schedule
21.12.2019
preemptive(например, факториальный алгоритм) иNon-preemptive(например, функция Аккермана). Автор привел всего два примера, которые я привел, не объясняя эту раздвоение должным образом. Является ли эта бифуркация такой же, как хвостовые и нехвостовые рекурсивные функции? - person RBT   schedule 23.09.2016