当然,F#和C#都编译成IL而CLR JITter完成了大部分的工作,但是我想知道F#语言或其核心库中是否隐含了与C#相比性能较差的内容?
另外,在.net框架中使用函数式编程有什么东西可能会使它比C#慢吗?
我当然会坐下来测量差异,因为这确实是确定的唯一真正的方法,但我只是想知道是否有人对此话题有任何广泛的了解.
也可以看看
C#/ F#性能比较
程序F#比C#更有效(执行方式)吗?
JaredPar.. 6
没有任何内在因素可以使一种语言比另一种语言更快.它们都运行在CLR上,因此具有与CLR上运行的任何语言大致相同的性能特征.虽然这些功能会影响性能,但各自的语言都有一些功能.
尾递归就是一个很好的例子.如果您编写一个大量使用尾递归的F#应用程序,编译器将尝试将其重写为迭代循环,从而消除递归惩罚.另外,F#使用.tail IL操作码来请求CLR尽可能地删除递归堆栈惩罚.
通过将一些F#continuation样本转换为C#然后插入大量数据集,可以很容易地证明这一点.F#将起作用,C#最终会崩溃.
http://blogs.msdn.com/jaredpar/archive/2008/11/13/comparing-continuations-in-c-and-f-part-3-double-wrong.aspx
但这并不一定是C#的缺陷.C#并不意味着用连续语写,而在F#中肯定是这种情况.实际上,在C#中编写用于F#的算法并不会产生如此好的结果,这并不奇怪.
相反,C#迭代器通常比F#序列表达式更有效.原因是C#迭代器是非常有效的状态机,而F#是继续传递.
一般而言,在线程的绝对中,如果您使用这些语言,则它们将具有类似的性能特征.
没有任何内在因素可以使一种语言比另一种语言更快.它们都运行在CLR上,因此具有与CLR上运行的任何语言大致相同的性能特征.虽然这些功能会影响性能,但各自的语言都有一些功能.
尾递归就是一个很好的例子.如果您编写一个大量使用尾递归的F#应用程序,编译器将尝试将其重写为迭代循环,从而消除递归惩罚.另外,F#使用.tail IL操作码来请求CLR尽可能地删除递归堆栈惩罚.
通过将一些F#continuation样本转换为C#然后插入大量数据集,可以很容易地证明这一点.F#将起作用,C#最终会崩溃.
http://blogs.msdn.com/jaredpar/archive/2008/11/13/comparing-continuations-in-c-and-f-part-3-double-wrong.aspx
但这并不一定是C#的缺陷.C#并不意味着用连续语写,而在F#中肯定是这种情况.实际上,在C#中编写用于F#的算法并不会产生如此好的结果,这并不奇怪.
相反,C#迭代器通常比F#序列表达式更有效.原因是C#迭代器是非常有效的状态机,而F#是继续传递.
一般而言,在线程的绝对中,如果您使用这些语言,则它们将具有类似的性能特征.
一个很好的例子是eratosthenes的筛子.
一位同事和我在C#和F#中写过类似的筛子.C#版本的性能几乎比我的同事编写的功能对应物慢10倍.
可能已经清理过C#版本中的一些低效率,但F#版本明显更快.
这类问题有助于用函数式语言编写.
希望这会有所帮助.
编辑 -
这是使用与F#的List.Partition类似功能的C#示例之一.我会继续寻找F#的例子.我有几百个可以进行的项目,只需要对我所有的东西进行分类就可以找到它(我保存了所有我试过的东西,所以这可能很费时间.大声笑)
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ListPartitionTest { public static class IEnumerableExtensions { public static KeyValuePair, IEnumerable > Partition (this IEnumerable items, Func f) { return items.Aggregate( new KeyValuePair , IEnumerable >(Enumerable.Empty (), Enumerable.Empty ()), (acc, i) => { if (f(i)) { return new KeyValuePair , IEnumerable >(acc.Key.Concat(new[] { i }), acc.Value); } else { return new KeyValuePair , IEnumerable >(acc.Key, acc.Value.Concat(new[] { i })); } }); } } class PrimeNumbers { public int Floor { get; private set; } public int Ceiling { get; private set; } private IEnumerable _sieve; public PrimeNumbers(int floor, int ceiling) { Floor = floor; Ceiling = ceiling; } public List Go() { _sieve = Enumerable.Range(Floor, (Ceiling - Floor) + 1).ToList(); for (int i = (Floor < 2) ? 2 : Floor; i <= Math.Sqrt(Ceiling); i++) { _sieve = _sieve.Where(x => (x % i != 0 && x != i)); foreach (int x in _sieve) { Console.Write("{0}, ", x); } Console.WriteLine(); } return _sieve.ToList(); } } class Program { static void Main(string[] args) { System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch(); int floor = 1; int ceiling = 10; s.Start(); PrimeNumbers p = new PrimeNumbers(floor, ceiling); p.Go(); //foreach (int i in p.Go()) Console.Write("{0} ", i); s.Stop(); Console.WriteLine("\n{0} to {1} completed in {2}", floor, ceiling, s.Elapsed.TotalMilliseconds); Console.ReadLine(); } } }