我一直在寻找一种方法,使用.NET进行适当的算法编码,具有现代语言的所有优点(例如,我喜欢强类型检查,运算符重载,lambda,泛型算法)。通常我用C ++编写算法(主要是图像处理)。由于F#作为一种语言似乎很有趣,我玩了一下,但似乎很慢。作为一个最简单的测试我只做了一些数组操作 - >图像的亮度增加:
let r1 = rgbPixels |> Array.map (fun x -> x + byte(10) )
它似乎是比对比C ++实现慢至少8倍的因素 - 对于更复杂的算法来说更糟糕,例如2D卷积。 有没有更快的方法或我错过任何特定的编译器设置(是的,建立发布优化...)? 我愿意为这个好的和高的抽象付出代价,但这样的开销并不好(我需要在8个内核上进行并行化以补偿:)) - 至少它会破坏进一步学习的动机......我的其他选择将我更重的算法留在C ++中并与manged C ++接口,但这并不好,因为维护托管包装将是一个很大的负担。
答案 0 :(得分:6)
如果你担心性能,要记住的一个重要事项是默认情况下F#不会改变任何东西。这需要复制许多天真的算法实现,例如您描述的算法。
编辑:我不知道为什么,但是对以下代码的简单测试会给Array.map
提供较差的结果。请务必分析在执行这些优化时尝试的任何算法。但是,我在for
和map
之间得到了非常相似的结果。
Array.map
为操作结果创建一个新数组,而不是Array.iteri
。
rgbPixels |> Array.iteri (fun i x -> rgbPixels.[i] <- x + 10uy)
请注意,这可以包含在您自己的模块中,如下所示
module ArrayM =
let map f a = a |> Array.iteri (fun i x -> a.[i] <- f x)
不幸的是,这是一个必要的恶魔,因为函数式编程的主要租户之一就是坚持不可变对象,就像算法允许的那样,然后一旦完成,就转换为性能至关重要的突变。如果你知道你的表现从一开始就很重要,你需要从这些帮助者开始。
另请注意,可能有一个库提供此功能,我只是不知道它在手边。
答案 1 :(得分:5)
我认为可以说,惯用的F#经常无法与优化的C ++进行数组操作的性能相匹配,原因如下:
fun i -> ...
)通常会有一些开销。在紧密的循环中,与在循环体中完成的工作相比,这种小的开销最终会变得非常重要。在分类帐的另一边,