Old*_*vec 3 optimization f# function record
有没有理由说F#不够聪明才能优化以下代码?fast = 880和slow = 8090.
type Data = { fn: int * int -> int }
let fn (x, y) = x + y
let data = { fn = fn }
let mutable a = 0
let s = System.Diagnostics.Stopwatch()
s.Start()
for i in 0 .. 1000000000 do
a <- fn(i, i)
printfn "fast = %d" s.ElapsedMilliseconds
s.Restart()
for i in 0 .. 1000000000 do
a <- data.fn(i, i)
printfn "slow = %d" s.ElapsedMilliseconds
Run Code Online (Sandbox Code Playgroud)
有没有理由说F#不够聪明才能优化以下代码?
如果F#编译器能够优化这种情况,我会感到惊讶.最后,fn是一个记录字段,用于保存数据,而不是执行功能.
即使在非静态成员上,编译器也无法内联它们,因为这些成员受到环境变化的限制.通过声明let绑定,您具有静态环境的优势,并且编译器能够在一些简单的情况下内联.
实际上在这个例子中,fn函数是内联的(添加inline不会改变运行时间).缓慢的例子是您为拥有更强大的构造而付出的代价.
无论何时必须创建函数记录,请记住接口和对象表达式是更好的替代方案(更少的开销,更好的智能感知):
type Data2 =
abstract fn : int * int -> int
let data2 =
{ new Data2 with
member __.fn (x, y) = fn (x, y) }
s.Restart()
for i in 0 .. 1000000000 do
a <- data2.fn(i, i)
printfn "a bit slow = %d" s.ElapsedMilliseconds
Run Code Online (Sandbox Code Playgroud)
这是我在F#Interactive 64位中执行的结果:
fast = 614
slow = 7498
a bit slow = 2765
Run Code Online (Sandbox Code Playgroud)
因此,基于接口的方法比基于记录的方法快3倍,比内联方法慢3倍.