【问题标题】:Terrific performance difference between almost equal methods几乎相同的方法之间的巨大性能差异
【发布时间】:2012-01-12 15:58:22
【问题描述】:

在处理一个项目时,我无意中注意到,在启用优化的情况下,只有一个额外(未使用)参数的相同方法的运行速度甚至比另一个快十倍。

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.formatStream.format1 之间的唯一区别只是 o 参数,而且该方法本身并未使用该参数。

编译器如何以如此不同的方式处理两个几乎相同的方法?

编辑:感谢您的解释,并为无知感到抱歉。

【问题讨论】:

  • 您运行了多少次迭代来获得时间?一?一百万?您需要使您的示例足够广泛,以消除缓存效果、内核调度等。

标签: performance optimization compiler-construction f#


【解决方案1】:

问题是当你只用一个参数调用Format1 时,它只返回一个函数。它还没有进行实际的格式化。这意味着,如果您比较以下各项的性能:

Stream.Format 42
Stream.Format1 42

...那么您实际上是在比较第一种情况下实际格式化(创建数组并在其中写入一些内容)的性能和只返回函数值而不执行任何操作的代码的性能。

如果您没有使用format1o 参数做任何事情,那么您可以只传递一些虚拟值,以实际评估函数并获得结果。那么你应该得到类似的性能:

Stream.Format 42
Stream.Format1 42 ()

【讨论】:

    【解决方案2】:

    Format 实际上调用了Array.zeroCreate l |&gt; fun a -&gt; (f(x, 0, a) |&gt; ignore; a)

    Format1 返回一个函数,当传递一个对象时调用Array.zeroCreate l |&gt; fun a -&gt; (f(x, 0, a) |&gt; ignore; a)

    即,一个做实际工作,另一个只是部分功能应用;后者显然更快。

    如果您不熟悉偏函数应用程序,请阅读 F# 文档中标题为“参数的部分应用程序”的部分:Functions (F#)

    【讨论】:

      猜你喜欢
      • 2023-03-09
      • 1970-01-01
      • 2021-03-07
      • 2014-06-20
      • 1970-01-01
      • 1970-01-01
      • 2017-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多