Như các câu trả lời khác đã đề cập, CLR không hỗ trợ tối ưu hóa cuộc gọi đuôi và có vẻ như nó đã được cải tiến trong lịch sử. Nhưng hỗ trợ nó trong C # có một Proposal
vấn đề mở trong kho lưu trữ git cho việc thiết kế ngôn ngữ lập trình C # Hỗ trợ đệ quy đuôi # 2544 .
Bạn có thể tìm thấy một số chi tiết và thông tin hữu ích ở đó. Ví dụ @jaykrell được đề cập
Hãy để tôi đưa ra những gì tôi biết.
Đôi khi gọi trước là một hiệu suất đôi bên cùng có lợi. Nó có thể tiết kiệm CPU. jmp rẻ hơn call / ret Nó có thể tiết kiệm ngăn xếp. Chạm vào ít ngăn xếp hơn sẽ tạo ra vị trí tốt hơn.
Đôi khi tailcall làm giảm hiệu suất, stack win. CLR có một cơ chế phức tạp, trong đó truyền nhiều tham số đến callee hơn là người gọi nhận được. Ý tôi là cụ thể hơn không gian ngăn xếp cho các tham số. Điều này là chậm. Nhưng nó bảo tồn ngăn xếp. Nó sẽ chỉ làm điều này với phần đuôi. tiếp đầu ngữ.
Nếu các tham số của người gọi lớn hơn tham số callee, thì đó thường là một biến đổi win-win khá dễ dàng. Có thể có các yếu tố như tham số-vị trí thay đổi từ được quản lý thành số nguyên / float và tạo các Bản đồ StackMap chính xác, v.v.
Bây giờ, có một góc độ khác, đó là các thuật toán yêu cầu loại bỏ cuộc gọi riêng, nhằm mục đích có thể xử lý dữ liệu lớn tùy ý với ngăn xếp cố định / nhỏ. Đây không phải là về hiệu suất, mà là về khả năng chạy.
Ngoài ra, hãy để tôi đề cập đến (như thông tin bổ sung), Khi chúng tôi đang tạo một lambda đã biên dịch bằng cách sử dụng các lớp biểu thức trong System.Linq.Expressions
không gian tên, có một đối số có tên là 'tailCall' được giải thích trong nhận xét của nó
Một bool cho biết liệu tối ưu hóa cuộc gọi đuôi có được áp dụng khi biên dịch biểu thức đã tạo hay không.
Tôi chưa thử nó và tôi không chắc nó có thể giúp ích như thế nào liên quan đến câu hỏi của bạn, nhưng Có lẽ ai đó có thể thử nó và có thể hữu ích trong một số trường hợp:
var myFuncExpression = System.Linq.Expressions.Expression.Lambda<Func< … >>(body: … , tailCall: true, parameters: … );
var myFunc = myFuncExpression.Compile();
preemptive
(ví dụ: thuật toán giai thừa) vàNon-preemptive
(ví dụ: hàm ackermann). Tác giả chỉ đưa ra hai ví dụ mà tôi đã đề cập mà không đưa ra lý do xác đáng đằng sau sự phân đôi này. Sự phân đôi này có giống với các hàm đệ quy đuôi và không đuôi không?