当然,F#和C#都编译到IL并且CLR JITter完成了大部分的工作,但我想知道F#语言或其核心库中是否隐含了与C#相比性能较差的内容?< / p>
此外,在.net框架中使用函数式编程是否有什么东西可以使它比C#慢?
我会坐下来衡量当然的差异,因为这确实是唯一真正知道的方法,但我只是想知道是否有人对此主题有任何广泛的了解
答案 0 :(得分:6)
没有任何内在因素可以使一种语言比另一种语言更快。它们都运行在CLR上,因此具有与CLR上运行的任何语言大致相同的性能特征。虽然这些功能会影响性能,但各自的语言都有。
尾递归就是一个很好的例子。如果您编写一个大量使用尾递归的F#应用程序,编译器将尝试将其重写为迭代循环,从而消除递归惩罚。另外,F#使用.tail IL操作码来请求CLR尽可能地删除递归堆栈惩罚。
通过将一些F#continuation样本转换为C#然后插入大量数据集,可以很容易地证明这一点。 F#将起作用,C#最终会崩溃。
但这不一定是C#的缺陷。 C#并不意味着用连续语写,而在F#中肯定是这样。事实上,在C#中编写用于F#的算法并不会产生如此好的结果,这并不奇怪。
相反,C#迭代器通常比F#序列表达式更有效。原因是C#迭代器是非常有效的状态机,而F#是继续传递。
一般而言,在线程的绝对中,如果您使用这些语言,则它们将具有类似的性能特征。
答案 1 :(得分:5)
一个很好的例子是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<T>, IEnumerable<T>> Partition<T>(this IEnumerable<T> items, Func<T, bool> f)
{
return items.Aggregate(
new KeyValuePair<IEnumerable<T>, IEnumerable<T>>(Enumerable.Empty<T>(), Enumerable.Empty<T>()),
(acc, i) =>
{
if (f(i))
{
return new KeyValuePair<IEnumerable<T>, IEnumerable<T>>(acc.Key.Concat(new[] { i }), acc.Value);
}
else
{
return new KeyValuePair<IEnumerable<T>, IEnumerable<T>>(acc.Key, acc.Value.Concat(new[] { i }));
}
});
}
}
class PrimeNumbers
{
public int Floor { get; private set; }
public int Ceiling { get; private set; }
private IEnumerable<int> _sieve;
public PrimeNumbers(int floor, int ceiling)
{
Floor = floor;
Ceiling = ceiling;
}
public List<int> 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();
}
}
}