在处理项目时我意外地注意到只有一个额外(未使用)参数的相同方法运行速度比另一个快十倍,并且启用了优化。
type Stream () =
static member private write (x, o, a : byte[]) = (for i = 0 to 3 do a.[o + i] <- byte((x >>> 24 - i * 8) % 256)); 4
static member private format f x l = Array.zeroCreate l |> fun a -> (f(x, 0, a) |> ignore; a)
static member private format1 f x l o = Array.zeroCreate l |> fun a -> (f(x, 0, a) |> ignore; a)
static member Format (value : int) = Stream.format (fun (x: int, i, a) -> Stream.write(x, i, a)) value 4
static member Format1 (value : int) = Stream.format1 (fun (x: int, i, a) -> Stream.write(x, i, a)) value 4
经过测试,Stream.Format1
的运行速度比Stream.Format
快得多,但私有成员Stream.format
和Stream.format1
之间的唯一差异只是o
参数,此外,该方法本身未使用它。
编译器如何以不同的方式处理两种几乎相同的方法?
编辑:感谢您的解释并抱歉无知。
答案 0 :(得分:8)
问题是当你用一个参数调用Format1
时,它只返回一个函数。它还没有进行实际的格式化。这意味着如果您比较以下的表现:
Stream.Format 42
Stream.Format1 42
...然后你实际上比较了第一种情况下实际格式化(创建数组并在其中写入内容)的性能以及只是返回函数值而不做任何事情的代码性能。
如果您没有使用o
的{{1}}参数,那么您可以传入一些虚拟值,以实际评估函数并获得结果。然后你应该得到类似的表现:
format1
答案 1 :(得分:4)
Format
实际上会调用Array.zeroCreate l |> fun a -> (f(x, 0, a) |> ignore; a)
。
Format1
返回一个函数,该函数在传递对象时调用Array.zeroCreate l |> fun a -> (f(x, 0, a) |> ignore; a)
。
即,一个人做实际工作,另一个人只是部分功能应用;后者显然更快。
如果您不熟悉部分功能应用程序,那么F#docs中标题为“部分应用参数”的部分值得一读:Functions (F#)