【问题标题】:How well does F# perform compared to C#? [duplicate]与 C# 相比,F# 的性能如何? [复制]
【发布时间】:2009-01-24 14:12:41
【问题描述】:

当然,F# 和 C# 都编译为 IL 并且 CLR JITter 完成了大部分艰苦的工作,但是我想知道 F# 语言或其核心库中是否有任何隐含的东西导致与 C# 相比性能较差?

此外,在 .net 框架中使用函数式编程是否有任何可能使其比 C# 慢的地方?

当然,我会坐下来衡量差异,因为这确实是唯一可以确定的真正方法,但是我只是想知道是否有人对这个主题有任何广泛的了解.

另见

【问题讨论】:

  • 只是把它扔在那里,但应将重复的内容编辑到原始帖子中,IMO。更容易找到答案,因为重复和类似问题的链接就在那里,清晰可见。
  • 不确定我是否同意所有重复的标记 - 新问题非法新答案、新观点和新示例,我认为人们应该放松一点:)
  • 嗯,我确实搜索过骗子,但没有找到...!随意关闭它。

标签: c# performance f#


【解决方案1】:

没有什么内在因素可以使一种语言比另一种更快。它们都在 CLR 上运行,因此具有与在 CLR 上运行的任何语言大致相同的性能特征。尽管不同语言的某些特性确实会影响性能。

尾递归就是一个很好的例子。如果您编写的 F# 应用程序大量使用尾递归,编译器将尝试将其重写为迭代循环以消除递归损失。此外,F# 使用 .tail IL 操作代码来要求 CLR 在可能的情况下消除递归堆栈惩罚。

通过将一些 F# 延续示例转换为 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# 是连续传递。

不过,一般来说,在没有线程的情况下,如果您按照预期使用的语言使用它们,它们将具有相似的性能特征。

【讨论】:

  • 在下一个版本中,F# 序列表达式将编译为状态机,huzzah!
  • @Brian,很高兴听到这个消息!
【解决方案2】:

一个很好的例子是埃拉托色尼筛。

我和一位同事用 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();
        }
    }
}

【讨论】:

  • 并排查看代码示例会很有趣...
  • 我会看看能不能找到它们,然后我会发布它们。 F# 中最节省时间的是 List.Partition。在 C# 中,我们使用的解决方案是一个大的 List.Aggregate 函数来做类似的事情。
  • 我认为代码大部分时间都在写入控制台...
猜你喜欢
  • 1970-01-01
  • 2011-05-20
  • 1970-01-01
  • 2011-03-22
  • 2021-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-07
相关资源
最近更新 更多