function - 使用 F# 优化记录中的函数值访问

标签 function optimization f# record

是否有什么原因导致 F# 不够聪明,无法优化以下代码? 快 = 880慢 = 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

最佳答案

Is there any reason why F# is not clever enough to optimize the following code?

如果 F# 编译器能够优化这种情况,我会感到惊讶。最后,fn是一个记录字段,用于保存数据,而不是执行函数。

即使对于非静态成员,编译器也无法内联它们,因为这些成员受到不断变化的环境的限制。通过声明 let 绑定(bind),您可以享受静态环境的优势,并且编译器能够在一些简单的情况下内联。

事实上,在此示例中,fn 函数是内联的(添加 inline 不会改变运行时间)。缓慢的例子是您为拥有更强大的构造而付出的代价。

每当您必须创建函数记录时,请记住接口(interface)和对象表达式是更好的选择(更少的开销,更好的智能感知):

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

这是我在 F# Interactive 64 位中执行得到的结果:

fast = 614
slow = 7498
a bit slow = 2765

因此,基于接口(interface)的方法比基于记录的方法快 3 倍,比内联方法慢 3 倍。

关于function - 使用 F# 优化记录中的函数值访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16305496/

相关文章:

python - 函数不返回 pyspark DataFrame

sql-server-2008 - Sql Server 中的错误函数

f# - 如何循环遍历有区别的联合案例并对其调用其成员函数?

javascript - 需要优化if语句

php - 更新数据库中序列化列的最佳方法

python - 在 Deedle 中使用默认值将列添加到数据框

f# - F#交换矩阵行的简单方法

r - 根据r中的列名从列表中提取数据框

Ruby:如何将函数映射到散列

python - 优化路线上另外 2 个卫生间的位置 (python)