2009-01-24 98 views
4

當然,F#和C#都編譯爲IL,而CLR JITter完成了大部分的努力工作,但是我想知道F#語言或其核心庫中是否有隱含的內容導致與C#相比性能較低?與C#相比,F#的性能如何?

另外,在.net框架中使用函數式編程有沒有什麼可能使它比C#慢呢?

我打算坐下來,尺寸當然不同,因爲這確實是唯一真正知道的方法,但我只是想知道是否有人對這個主題有廣泛的知識。

此外
+0

同一問題在這裏:http://stackoverflow.com/questions/144227/cf-performance-comparison – splattne 2009-01-24 14:30:09

+0

和這裏:http://stackoverflow.com/questions/142985/is-a-program-f-any-更有效的執行方式比c更容易 – splattne 2009-01-24 14:32:22

+0

只是把它扔到那裏,但是重複的東西應該被編輯到IMO的原始文章中。使答案更容易找到答案,因爲重複和類似問題的鏈接就在那裏,清晰可見。 – 2009-01-24 14:58:25

回答

5

見一個很好的例子是埃拉託塞尼的篩。

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

沒有什麼內在的東西讓一種語言比另一種語言更快。它們都運行在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#則是延續傳遞。

一般來說,雖然在線程的缺失情況下,如果您使用的語言是打算使用的,它們將具有相似的性能特徵。