【问题标题】:What makes FSharpFunc<> faster than Func<>?是什么让 FSharpFunc<> 比 Func<> 快?
【发布时间】:2013-05-03 23:41:31
【问题描述】:

我很好奇 FSharpFunc 的性能增强。 是不是它不包含多个委托,所以在触发函数调用时不需要循环所有引用?还有什么?

【问题讨论】:

    标签: f# delegates


    【解决方案1】:

    我认为使用FSharpFunc&lt;&gt; 而不是Func&lt;&gt; 或任何其他委托的主要动机是你不能创建一个从委托类型继承的类(起初,这听起来很合理,但在.NET 中,委托实际上只是一些特殊的类,因此原则上可能允许这样做)。为什么需要这个?

    如果您在 F# 中编写函数,那么它(在相对少数但非常重要的情况下)以柯里化形式处理。例如 int -&gt; int -&gt; int 实际上是一个函数类型 int -&gt; (int -&gt; int) (currying 意味着你只使用单个参数的函数编写一个函数 - 如果你用第一个参数调用它,你会得到一个函数作为结果,你可以调用带有第二个参数的返回函数)。

    如果 F# 使用委托,则类型将类似于 Func&lt;int, Func&lt;int, int&gt;&gt;。正如 Brian 提到的,调用 f x y 将被转换为两个调用:f(x)(y)。然而,这种调用是最常见的(仅指定一个参数称为部分函数应用程序)。所以,当 F# 编译这样的函数时,它会创建一个带有优化的调用方法的继承类,这样就可以将其调用为f.Invoke(x, y)

    class @some_F#_name@ : Func<int, Func<int, int>> {
       public int Invoke(int arg1, int arg2) { /* optimized call */ }
    }
    

    不幸的是,不可能通过继承标准Func(因为它是一个委托)来创建这样的类,所以 F# 必须声明自己的类型,它可以用作基类...

    【讨论】:

    • 谢谢托马斯。这意味着在不进行 C# 互操作时不会调用它,我理解正确吗?
    • 对于互操作,我总是将 F# 代码公开为采用普通 C# Func&lt;...&gt; 的方法,以使 C# 互操作尽可能顺利。
    • 让我换个说法:有什么理由在常规(非互操作)F# 代码中使用它吗?
    【解决方案2】:

    (我认为它们现在被称为 FSharpFunc 而不是 FastFunc。)

    它表示为具有单个抽象方法 (Invoke) 的类型,我认为这可以避免使用真正的委托时产生的一些开销。对于多个 curried 参数,它使您能够“一次”而不是一个一个地调用所有参数(例如,f x y 可以在 CLR 上调用为f(x,y) 而不是f(x)(y)

    还有别的吗?我现在不记得了。您可以在 CTP 版本附带的源代码分发中查看 FSharp.Core 中 prim-types.fs 中的源代码。

    【讨论】:

    • 出于好奇,在编写普通 let 绑定时是否隐式使用了 FSharpFunc?
    • 任何时候你需要用 X->Y 类型表示一个 object,我认为它会被表示为 FSharpFunc 的一个实例。当您定义 let-bound 函数时,这些可以表示为 CLR 的普通方法,但如果您将函数用作值(例如,将其作为参数传递给 List.map 或诸如此类),那么它将通过一个表示FSharpFunc。
    猜你喜欢
    • 2019-03-01
    • 2012-11-30
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    • 2020-08-12
    • 2014-03-17
    • 2016-08-18
    • 1970-01-01
    相关资源
    最近更新 更多