Performance F#似乎比其他语言慢。。。我能做些什么来加速它?

Performance F#似乎比其他语言慢。。。我能做些什么来加速它?,performance,f#,benchmarking,Performance,F#,Benchmarking,我喜欢F#;我真的,真的。被“函数式编程”的bug所困扰,我强迫自己在有机会的时候使用它。事实上,我最近(在一周的假期中)用它来帮助你 然而,我迄今为止的尝试(见与我第一次尝试相关的一个问题)似乎表明,尽管毫无疑问是美丽的。。。在我使用过的所有语言中,F#的执行速度最慢 我的代码是否有问题 我详细地解释了我在实验中所做的,在我的实验中,我看到OCaml和其他团队的运行速度比F#快5到35倍 只有我有这样的经历吗?我觉得很沮丧,我最喜欢的语言也是最慢的语言——有时到目前为止 编辑:各种语言形式的直

我喜欢F#;我真的,真的。被“函数式编程”的bug所困扰,我强迫自己在有机会的时候使用它。事实上,我最近(在一周的假期中)用它来帮助你

然而,我迄今为止的尝试(见与我第一次尝试相关的一个问题)似乎表明,尽管毫无疑问是美丽的。。。在我使用过的所有语言中,F#的执行速度最慢

我的代码是否有问题

我详细地解释了我在实验中所做的,在我的实验中,我看到OCaml和其他团队的运行速度比F#快5到35倍

只有我有这样的经历吗?我觉得很沮丧,我最喜欢的语言也是最慢的语言——有时到目前为止

编辑:各种语言形式的直接GitHub链接

EDIT2:多亏了托马斯和丹尼尔,速度大大提高:

  • 最大的速度提升:从“ref”到“mutable”的速度提升了30%
  • 删除异常并使用while/flagChecks,得到了另外16%的结果
  • 从受歧视的联合切换到枚举,得到了另外5%的回报
  • “内联”给出了0.5-1%
EDIT3:Jon Harrop博士加入了这场战斗:通过让记分板直接在“枚举”数据版本上运行,速度提高了60%。现在,F版本的命令版本比C++运行速度慢3-4倍,这是基于VM的运行时的一个好结果。我认为这个问题已经解决了——谢谢大家!p> EDIT4:在合并所有优化之后,这些就是结果(命令式风格的F#达到C#-现在,如果我也能对函数式风格做点什么就好了!)

  • real 0m0.221s:那是C++
  • < Le> 0M0.67 6S:C是(命令,C++镜像)< /LI> <0>实数0M0.704s:这是F(命令,C++镜像)< /LI> <0:Leal0M0.75 3S:那是OCaml(命令,C++镜像)
  • real 0m0.989s:这是OCaml(功能性)
  • real 0m1.064s:那是Java(命令式)
  • real 0m1.955s:这是F#(功能性)

这本身不是一个答案,但您是否尝试过用F#和C#编写完全相同的代码,即命令式F#代码?速度应该差不多。如果您将简洁的函数代码与大量使用高阶函数、序列表达式、惰性值、复杂模式匹配等进行比较——所有这些都允许代码更短、更清晰(可读性更强、更易于维护)——那么,通常会有一个权衡。一般来说,开发/维护时间远大于执行时间,因此通常认为这是一种理想的权衡

一些参考资料:



需要考虑的另一点是:在函数式语言中,您的工作级别更高,因此很容易忽略操作成本。例如,
Seq.sort
看起来很天真,但天真地使用它会破坏性能。我建议仔细研究一下你的代码,一路上问问自己是否了解每项操作的成本。如果您没有反思的感觉,那么更快的方法当然是使用探查器。

除非您能够给出大小合理的代码示例,否则很难判断。无论如何,命令式F#版本应该和命令式C#版本一样高效。我认为一种方法是对两者进行基准测试,看看是什么导致了差异(然后有人可以帮助加快速度)

我简要地看了一下您的代码,下面是一些分类(未经测试)的建议

  • 您可以使用枚举替换区分的union
    单元格
    (这意味着您将使用值类型和整数比较,而不是引用类型和运行时类型测试):

  • 您可以将一些普通函数标记为
    inline
    。例如:

    let inline myincr (arr:int array) idx =
      arr.[idx] <- arr.[idx] + 1
    
    让内联myincr(arr:int数组)idx=
    
    我认为你的问题很好,但需要一个更积极的问题,比如标题。也许像“F#似乎比其他语言慢。我怎样才能加快速度?”我同意@Zan的说法。你的问题在目前的状态下似乎是一个咆哮。我认为这个问题更像是一个咆哮。你引用了一篇博客文章,但不太可能有人为了回答你的问题而阅读一篇长文章。你能改进这个问题并找到一段F#速度较慢、足够短的代码来解决问题吗?@ttsiodras-那么,Jon Harrop是如何在第一个案例中找到解决方案的?我想他是在程序中发现了瓶颈。然后他用更快的东西代替了慢的部分。要问一个问题,你需要一个合理大小的代码样本(某人可以标杆)或者知道瓶颈是什么(这样某人可以提出更有效的方法来建议)。你的C++代码使用了板> /Cord>数组,而你的F实现则不必要地复制到内部循环中。您还使用了像
    [|(0,0);(1,1);(2,2);(3,3)|]
    这样的数组,这些数组显然毫无意义。修正这些明显的差异会立即使F#比以前快2倍。事实上,我做到了——如果你在博客文章中看到我的“移动到命令式风格”部分,你会看到,一旦我用C#编码(并且得到了2倍于F#),我就用命令式风格为OCaml和F#编写代码。F#仍然远远落后于C#(6秒对3秒,2倍)。更不用说OcAML有1.4和C++有0.2秒…我想看看你的命令F代码。没有理由认为它的性能应该与C#有很大的不同。无论如何——正如在博客文章中所说,代码存在于GitHub中:-在F#文件夹中导航,它包含命令式和函数式解决方案。对不起,我想我很懒,我没有读一篇很长的博客文章谢谢你的链接。@ttsiodras:酷。我仍然推荐分析,直到它与C。这种差异肯定是有原因的。是
    let inline myincr (arr:int array) idx =
      arr.[idx] <- arr.[idx] + 1