我很好奇F#性能与C ++性能相比如何?我问了一个关于Java的类似问题,我得到的印象是Java不适合重编码。
我已经读过F#应该具有更高的可扩展性和更高的性能,但这种真实性能与C ++相比如何呢?关于当前实施的具体问题是:
由于
答案 0 :(得分:62)
我很好奇F#性能与C ++性能的比较?
根据应用的不同而变化很大。如果您在多线程程序中广泛使用复杂的数据结构,那么F#可能是一个巨大的胜利。如果你的大部分时间花在紧密的数字循环中,那么变异的数组可能会快2-3倍。
案例研究:光线追踪器我的基准here使用树进行分层剔除,并使用数字光线球体交叉代码生成输出图像。这个基准测试已有几年的历史了,多年来C ++代码已经被改进了几十次,并被成千上万的人阅读。在使用MSVC编译并使用OpenMP进行并行化时,Microsoft的Don Syme设法编写了一个比最快的C ++代码更快的F#实现。
我已经读过F#应该更具可扩展性和更高性能,但这种真实性能与C ++相比如何呢?
使用F#开发代码比使用C ++更容易,更快,这适用于优化和维护。因此,当您开始优化程序时,如果使用F#而不是C ++,相同的工作量将产生更大的性能提升。但是,F#是一种更高级别的语言,因此对性能的上限较低。因此,如果您有无限的时间来进行优化,理论上,您应该始终能够在C ++中生成更快的代码。
当然,这与C ++相比Fortran和Fortran在手写汇编程序方面的优势完全相同。
案例研究:QR分解这是LAPACK等图书馆提供的线性代数的基本数值方法。参考LAPACK实现是2,077行Fortran。我在80行代码中写了an F# implementation,达到了相同的性能水平。但参考实现并不快:像英特尔数学核心库(MKL)这样的供应商调优实现通常要快10倍。值得注意的是,我设法优化了我的F#代码超越在英特尔硬件上运行的英特尔实现的性能,同时保持我的代码在150行代码下并且完全通用(它可以处理单精度和双精度,并且复杂甚至是符号矩阵!):对于高薄矩阵,我的F#代码比英特尔MKL快3倍。
请注意,本案例研究的道德并不是您应该期望您的F#比供应商调整的库更快,而是即使像英特尔这样的专家如果只使用较低级别的话也会错过高效的高级优化语言。我怀疑英特尔的数值优化专家未能充分利用并行性,因为他们的工具使得它非常麻烦,而F#使它毫不费力。
浮点数有多好?
性能与ANSI C类似,但.NET无法提供某些功能(例如舍入模式)。
是否允许矢量指令
没有
对优化编译器有多友好?
这个问题没有意义:F#是Microsoft的专有.NET语言,只有一个编译器。
它有多大的记忆足迹?
空应用程序在这里使用1.3Mb。
是否允许对内存位置进行细粒度控制?
比大多数内存安全语言更好,但不如C语言好。例如,您可以通过将它们表示为“结构”来取消F#中的任意数据结构。
它是否具有分布式内存处理器的容量,例如Cray?
取决于“容量”的含义。如果您可以在Cray上运行.NET,那么您可以使用F#中的消息传递(就像下一种语言一样),但F#主要用于桌面多核x86计算机。
它涉及哪些特征可能对涉及大数处理的计算科学感兴趣?
内存安全意味着您不会遇到分段错误和访问冲突。 .NET 4中对并行性的支持很好。通过Visual Studio 2010中的F#交互式会话即时执行代码的能力对于交互式技术计算非常有用。
是否有使用它的实际科学计算实现?
我们用于F#科学计算的commercial products已经拥有数百名用户。
然而,您的提问线表明您将科学计算视为高性能计算(例如Cray)而非交互式技术计算(例如MATLAB,Mathematica)。 F#适用于后者。
答案 1 :(得分:42)
除了其他人所说的,还有一个关于F#的重点,那就是并行性。普通F#代码的性能由CLR决定,尽管您可以使用F#中的LAPACK,或者您可以使用C ++ / CLI作为项目的一部分进行本机调用。
但是,精心设计的功能程序往往更容易并行化,这意味着您可以通过使用多核CPU轻松获得性能,如果您正在进行一些科学计算,这些CPU绝对可用。以下是几个相关链接:
关于分布式计算,您可以使用可用于.NET平台的任何分布式计算框架。有一个MPI.NET项目,它适用于F#,但您也可以使用DryadLINQ,这是一个MSR项目。
答案 2 :(得分:40)
答案 3 :(得分:16)
与所有语言/性能比较一样,您的里程在很大程度上取决于您的编码能力。
F#是OCaml的衍生物。我很惊讶地发现OCaml在金融世界中被广泛使用,其中数字运算性能非常重要。我更惊讶地发现OCaml是速度更快的语言之一,其性能与最快的C和C ++编译器相当。
F#建立在CLR之上。在CLR中,代码以字节码的形式表示,称为公共中间语言。因此,如果代码写得很好,它可以从JIT的优化功能中受益,并且具有与C#(但不一定是C ++)相当的性能。
通过使用本机映像生成器(NGEN),可以在运行时之前的单独步骤中将CIL代码编译为本机代码。由于不再需要CIL到本机编译,这加速了软件的所有后续运行。
要考虑的一件事是像F#这样的函数式语言受益于更具说明性的编程风格。从某种意义上说,您过度使用C ++等命令式语言来指定解决方案,这限制了编译器的优化能力。从理论上讲,更具说明性的编程风格可为编译器提供额外的算法优化机会。
答案 4 :(得分:9)
这取决于你正在做什么样的科学计算。
如果您正在执行traditional heavy computing
,例如线性代数,各种优化,那么你不应该把你的代码放在.Net框架中,至少不适合F#。因为这是在算法级别,所以大多数算法必须以命令式语言编码,以便在运行时和内存使用方面具有良好的性能。其他人提到并行,我必须说当你做一些像SVD实现并行的低级别的东西时它可能是无用的。因为当你知道如何并行SVD时,你根本不会使用高级语言,Fortran,C或修改过的C(例如cilk)是你的朋友。
然而,今天的许多科学计算都不属于这种类型,这是某种高级应用,例如:统计计算和数据挖掘。在这些任务中,除了一些线性代数或优化之外,还有很多数据流,IO,预处理,做图形等。对于这些任务,F#非常强大,因为它简洁,功能,安全,易于平行等等。
正如其他人所说,.Net很好地支持平台调用,实际上MS内部的很多项目都使用.Net和P / Invoke来提高瓶颈性能。
答案 5 :(得分:7)
不幸的是,我认为你不会找到很多可靠的信息。 F#仍然是一种非常新的语言,所以即使它非常适合性能繁重的工作负载,仍然不会有那么多具有丰富经验的人报告。此外,性能很难准确测量,微基准测试难以概括。即使在C ++中,您也可以看到编译器之间的巨大差异 - 您是否想知道F#是否与任何 C ++编译器或假设的“最佳”C ++可执行文件竞争?
关于针对C ++的具体基准,这里有一些可能相关的链接:O'Caml vs. F#: QR decomposition; F# vs Unmanaged C++ for parallel numerics。请注意,作为F#相关材料的作者和作为F#工具的供应商,作者对F#的成功有着既得利益,所以请将这些说法与之相提并论。
我认为可以肯定的是,会有一些应用程序,其中F#在执行时间上具有竞争力,而其他一些应用程序可能不具备竞争力。在大多数情况下,F#可能需要更多内存。当然,最终的表现也将高度依赖于程序员的技能 - 我认为F#几乎可以肯定是一个更有效率的语言,可以为一个适度称职的程序员编程。此外,我认为目前,对于大多数任务而言,Windows上的CLR在大多数操作系统上的性能优于Mono,这可能也会影响您的决策。当然,由于F#可能比C ++更易于并行化,因此它还取决于您计划运行的硬件类型。
最终,我认为真正回答这个问题的唯一方法是编写代表你想要执行的计算类型的F#和C ++代码并进行比较。
答案 6 :(得分:4)
以下是我可以分享的两个例子:
矩阵乘法: 我有一篇博文comparing different matrix multiplication implementations。
LBFGS
我有一个使用LBFGS优化的大规模逻辑回归求解器,用C ++编码。实施得到了很好的调整。我修改了一些代码用C ++ / CLI编写代码,即我将代码编译成.Net。 .Net版本比不同数据集上的朴素编译版慢3到5倍。如果在F#中编写LBFGS代码,性能不能比C ++ / CLI或C#更好(但会非常接近)。
我在Why F# is the language for data mining上有另一篇文章,虽然与你在这里关注的性能问题没有太大关系,但它与F#中的科学计算密切相关。
答案 7 :(得分:3)
如果我说“在2 - 3年内再问”,我认为这将完全回答你的问题:-)
首先,不要指望F#与C#表示任何不同,除非你是故意进行一些复杂的递归,我猜你不是因为你问过数字。
浮点方面它肯定比Java更好,因为CLR并不针对跨平台的一致性,这意味着只要有可能,JIT就会达到80位。另一方面,除了观察变量的数量之外,你无法控制它,以确保有足够的FP寄存器。
矢量方面,如果你大声尖叫,可能会在2 - 3年内发生一些事情,因为Direct3D无论如何都要进入.NET作为通用API而在Xbox上运行的C#代码在Xbox上运行时,你可以接近裸机得到CLR。这仍然意味着你需要自己做一些中间代码。
所以不要指望CUDA甚至只能链接NVIDIA libs并开始使用。如果出于某种原因,你真的需要一种“功能性”语言,因为Haskell的设计是出于纯粹的必要性而对链接友好。
已经提到过Mono.Simd,虽然它应该可以反向移植到CLR,但实际上可能还有一些工作要做。
在social.msdn posting中有很多代码在.NET中使用SSE3,使用C ++ / CLI和C#,进行数组blitting,为perf等注入SSE3代码。
有人谈到在编译的C#上运行CECIL以将部件提取到HLSL中,编译成着色器并链接粘合代码来安排它(CUDA无论如何都做等效)但我认为没有任何可以运行的东西。
如果您想尽快尝试,可能对您有所帮助的事情是PhysX.Net on codeplex。不要指望它只是解包并做魔术。但是,ih目前是活跃的作者,代码是普通的C ++和C ++ / CLI,如果你想详细介绍并且可能使用类似的CUDA方法,yopu可能会从作者那里得到一些帮助。对于全速CUDA,您仍然需要编译自己的内核,然后只需与.NET接口,这样就可以更容易地实现这一部分。
有一个CUDA.NET lib应该是免费的,但页面只提供电子邮件地址,所以期待附加一些字符串,而作者写一个blog他并不特别谈论什么是在lib里面。
哦,如果你有预算哟可能会给Psi Lambda看一看(KappaCUDAnet是.NET部分)。显然他们将在11月抬高价格(如果这不是销售技巧: - )
答案 8 :(得分:1)
最后我知道,大多数科学计算仍然在FORTRAN中完成。它仍然比线性代数问题更快 - 不是Java,不是C,不是C ++,不是C#,不是F#。 LINPACK经过精心优化。
但是关于“你的里程可能会有所不同”的评论在所有基准测试中都是正确的。一揽子陈述(我的除外)很少是真的。
答案 9 :(得分:1)
首先,C比C ++快得多。所以如果你需要这么快的速度,你应该在c中创建lib等。
关于F#,大多数基准测试使用的Mono比MS CLR慢2 *,部分原因是它使用了boehm GC(他们有一个新的GC和LVVM,但这些还不成熟,不支持泛型等) 。
。语言本身被编译为IR(CIL),它与C ++一样高效地编译为本机代码。大多数GC语言都存在一个问题集,即大量可变写入(这包括上面提到的C ++ .NET)。并且有一个需要这个的科学问题集,这些在需要时应该使用本机库或使用Flyweight模式来重用池中的对象(这会减少写入)。原因是.NET CLR中存在写入障碍,当更新引用字段(包括框)时,它将在表中设置一个位,表示该表已被修改。如果您的代码包含大量此类写入,则会受到影响。
那就像C#这样的.NET应用程序在结构上使用了大量的静态代码,结构和ref / out可以产生类似C的性能,但很难像这样编码或维护代码(比如C)。
然而,F#闪耀的是不可变数据的parralelism,这些数据与更多基于读取的问题相关。值得注意的是,大多数基准测试的可变写入比实际应用程序要高得多。
关于浮点,你应该使用一个替代的lib(即.Net one)到oCaml,因为它很慢。 C / C ++可以更快地实现oCaml默认的低精度。
最后,我认为像C#,F#这样的高级语言和适当的分析将在相同的开发时间给你比c和C ++更好的表现。如果您将瓶颈更改为c lib pinvoke调用,您最终将获得关键区域的C类性能。也就是说,如果你有无限的预算,更关心速度,那么维护比C更方便(不是C ++)。