Một trong những điều tôi yêu thích về F # là một từ khóa thực sự inline
. Tuy nhiên, mặc dù nó cho phép viết các hàm thứ tự đầu tiên thực hiện giống như các khối mã được dán, nhưng mọi thứ không phải là màu hồng cho các hàm bậc cao hơn. Cân nhắcTại sao không thể trình biên dịch hàm F inline đầy đủ chức năng của hàm bậc cao hơn?
let inline add i = i+1
let inline check i = if (add i) = 0 then printfn ""
let inline iter runs f = for i = 0 to runs-1 do f i
let runs = 100000000
time(fun()->iter runs check) 1
time(fun()->for i = 0 to runs-1 do check i) 1
Kết quả là 244 ms
cho iter
và 61 ms
cho kiểm tra bằng tay. Hãy nghiên cứu sâu vào ILSpy. Chức năng liên quan được gọi cho cuộc gọi trực tiếp là:
internal static void [email protected](Microsoft.FSharp.Core.Unit unitVar0)
{
for (int i = 0; i < 100000000; i++)
{
if (i + 1 == 0)
{
Microsoft.FSharp.Core.PrintfFormat<Microsoft.FSharp.Core.Unit, System.IO.TextWriter, Microsoft.FSharp.Core.Unit, Microsoft.FSharp.Core.Unit> format = new Microsoft.FSharp.Core.PrintfFormat<Microsoft.FSharp.Core.Unit, System.IO.TextWriter, Microsoft.FSharp.Core.Unit, Microsoft.FSharp.Core.Unit, Microsoft.FSharp.Core.Unit>("");
Microsoft.FSharp.Core.PrintfModule.PrintFormatLineToTextWriter<Microsoft.FSharp.Core.Unit>(System.Console.Out, format);
}
}
}
Với add
được gạch chân. Các chức năng có liên quan để iter
là
internal static void [email protected](Microsoft.FSharp.Core.Unit unitVar0)
{
for (int i = 0; i < 100000000; i++)
{
[email protected](i);
}
}
internal static void [email protected](int i)
{
if (i + 1 == 0)
{
Microsoft.FSharp.Core.PrintfFormat<Microsoft.FSharp.Core.Unit, System.IO.TextWriter, Microsoft.FSharp.Core.Unit, Microsoft.FSharp.Core.Unit> format = new Microsoft.FSharp.Core.PrintfFormat<Microsoft.FSharp.Core.Unit, System.IO.TextWriter, Microsoft.FSharp.Core.Unit, Microsoft.FSharp.Core.Unit, Microsoft.FSharp.Core.Unit>("");
Microsoft.FSharp.Core.PrintfModule.PrintFormatLineToTextWriter<Microsoft.FSharp.Core.Unit>(System.Console.Out, format);
return;
}
}
Và chúng ta có thể thấy các hình phạt hiệu quả xuất phát từ một cấp thêm về mình. Như kiểm tra hiệu năng cho thấy, sự chuyển hướng này cũng không bị loại bỏ bởi trình biên dịch JIT. Có lý do gì khiến tại sao các hàm bậc cao không thể hoàn toàn được nội tuyến? Đây là một nỗi đau khi viết một hạt nhân tính toán.
thời gian combinator của tôi (mặc dù không thực sự liên quan ở đây) là
let inline time func n =
func() |> ignore
GC.Collect()
GC.WaitForPendingFinalizers()
let stopwatch = Stopwatch.StartNew()
for i = 0 to n-1 do func() |> ignore
stopwatch.Stop()
printfn "Took %A ms" stopwatch.Elapsed.TotalMilliseconds
Vui lòng xác nhận rằng bạn đã chạy chương trình này ở chế độ Phát hành mà không đính kèm trình gỡ rối. Ngoài ra, điểm chuẩn có vẻ hợp lệ. Bạn có thể cải thiện nó bằng cách tăng công việc lên 10 lần để tránh ảnh hưởng của chi phí một lần. – usr
@usr Có, tôi đã chạy nó mà không cần trình sửa lỗi và được biên dịch trong chế độ Phát hành. Có thể có không có nghi ngờ sự khác biệt hiệu suất là thực sự mặc dù bởi vì nó có thể được suy ra từ mã IL (chặn tối ưu hóa JIT). – Arbil
@Arbil Tôi đã liên kết với câu hỏi này trên một trong các chủ đề UserVoice Thiết kế Ngôn ngữ F # về phân tích nội tuyến: https://fslang.uservoice.com/forums/245727-f-language/suggestions/6137978-better-inlining-analysis -and-heuristic-algorithm –