다른 답변에서 언급했듯이 CLR은 테일 콜 최적화를 지원하며 역사적으로 점진적인 개선을 겪은 것 같습니다. 그러나 C #에서 지원하는 것은 Proposal
C # 프로그래밍 언어 Support tail recursion # 2544 의 설계를 위해 git 저장소에 공개 된 문제가 있습니다 .
여기에서 유용한 세부 정보와 정보를 찾을 수 있습니다. 예를 들어 @jaykrell이 언급되었습니다.
내가 아는 것을 알려주세요.
때때로 tailcall은 성능 윈윈입니다. CPU를 절약 할 수 있습니다. jmp는 call / ret보다 저렴합니다. 스택을 절약 할 수 있습니다. 더 적은 스택을 만지면 더 나은 지역성을 만듭니다.
때때로 tailcall은 성능 손실, 스택 승리입니다. CLR에는 호출자가 수신 한 것보다 더 많은 매개 변수를 호출자에게 전달하는 복잡한 메커니즘이 있습니다. 특히 매개 변수를위한 더 많은 스택 공간을 의미합니다. 이것은 느립니다. 그러나 스택을 절약합니다. 이것은 꼬리로만 할 것입니다. 접두사.
호출자 매개 변수가 수신자 매개 변수보다 스택 크기가 큰 경우 일반적으로 매우 쉬운 윈-윈 변환입니다. 매개 변수 위치가 관리 형에서 정수 / 부동 수로 변경되고 정확한 StackMaps 등을 생성하는 것과 같은 요인이있을 수 있습니다.
이제 고정 / 작은 스택으로 임의의 큰 데이터를 처리 할 수 있도록 테일 콜 제거를 요구하는 알고리즘의 또 다른 각도가 있습니다. 이것은 성능에 관한 것이 아니라 실행 능력에 관한 것입니다.
또한 (추가 정보로) 언급하겠습니다. System.Linq.Expressions
네임 스페이스의 표현식 클래스를 사용하여 컴파일 된 람다를 생성 할 때 'tailCall'이라는 인수가 있습니다.
생성 된 표현식을 컴파일 할 때 마무리 호출 최적화가 적용 될지 여부를 나타내는 부울입니다.
나는 아직 시도하지 않았고 귀하의 질문과 관련하여 어떻게 도움이 될 수 있는지 확실하지 않지만 아마도 누군가가 시도해 볼 수 있으며 일부 시나리오에서 유용 할 수 있습니다.
var myFuncExpression = System.Linq.Expressions.Expression.Lambda<Func< … >>(body: … , tailCall: true, parameters: … );
var myFunc = myFuncExpression.Compile();
preemptive
(예 : 계승 알고리즘)과Non-preemptive
(예 : ackermann의 함수) 두 가지로 나누는 데이터 구조에 관한 책을 읽었습니다 . 저자는이 분기 뒤에 적절한 추론을 제공하지 않고 내가 언급 한 두 가지 예를 제시했습니다. 이 분기는 꼬리 및 꼬리가 아닌 재귀 함수와 동일합니까?