2012-07-26 25 views
5

Basit bir senaryo var, burada derlenmiş bir ağacın performansını stok nesnelerinin bir listesinde sınamaya çalışıyorum. Aşağıda,Derlenmiş İfade Ağacı Performansı

kodudur. Derlenmiş derlenmiş ağaçların performansı, statik lambda çağrısından 5 kat daha yavaştır. Bunun, ifade derlenmiş ağaçla bekleyebilecek standart bir performans olup olmadığından emin değilim. Herhangi bir anlayış için minnettarım.

LambdaExpression(); 
List<Stock> stocks = new List<Stock>(); 
for (int ctr = 0; ctr <= 5000000; ctr++) 
{ 
    Stock stk1 = new Stock() { Price = ctr, Symbol = "A", CloseDate = DateTime.Now, FaceValue = ctr } ; 
    stocks.Add(stk1); 
} 
CompileTimeLamda(a); 
DynamicLambda(a); 


public static void LambdaExpression() 
{ 
    ParameterExpression CS1 = Expression.Parameter(typeof(Stock), "d"); 

    var line1 = Expression.Equal(Expression.Property(CS1, typeof(Stock).GetProperty("Symbol")), Expression.Constant("MSFT", typeof(string))); 
    var line2 = Expression.GreaterThan(Expression.Property(Expression.Property(CS1, typeof(Stock).GetProperty("CloseDate")),typeof(DateTime).GetProperty("Millisecond")), 
           Expression.Constant(0, typeof(int))); 
    var line3 = Expression.GreaterThan(Expression.Property(CS1, typeof(Stock).GetProperty("Price")), Expression.Constant((double)0, typeof(double))); 
    var line4 = Expression.And(line1,line2); 
    var line5 = Expression.OrElse(line4, line3); 

    func = Expression.Lambda<Func<Stock, bool>>(line5, new ParameterExpression[] { CS1 }).Compile(); 
} 


public static void DynamicLambda(List<Stock> stks) 
{ 
    Stopwatch watch = new Stopwatch(); 
    watch.Start(); 
    foreach (var d in stks) 
    { 
     func(d); 
    } 
    watch.Stop(); 
    Console.WriteLine("Dynamic Lambda :" + watch.ElapsedMilliseconds); 
} 

public static void CompileTimeLamda(List<Stock> stks) 
{ 
    Stopwatch watch = new Stopwatch(); 
    watch.Start(); 
    foreach (var d in stks) 
    { 
     if (d.Symbol == "MSFT" && d.CloseDate.Millisecond > 0 || 
            (d.Price) > 0) ; 
    } 
    watch.Stop(); 
    Console.WriteLine("Compile Time Lamda " +watch.ElapsedMilliseconds); 
} 
+3

Derlenmiş IL'yi kontrol edin; Optimizer tüm kodunuzu öldürebilir. – SLaks

+0

Aslında 2 lambda ifadesini karşılaştırmıyorsunuz. İkincisi sadece derlenmiş koddur, yani delege yoktur. Delegenin onu yavaşlatması oldukça mümkün. – MikeKulls

+0

Elmaları ve portakalları karşılaştırıyor gibi görünüyorsunuz. "Derleme zamanı lambda" hiç bir lambda kullanmaz. Ayrıca, derleyici muhtemelen döngüden uzaklaşıyor çünkü gerçekten hiçbir şey yapmıyorsunuz (boş deyim ";") –

cevap

2

fark derleyici bir lambda kullanarak, Ayrıca ... daha fazla bilgi sahip ve oldukça zamanında yerine derleme zamanında derlemek eğer kod optimize etmek için detaylı çaba harcamadan ile ilgisi var, sahip bir daha "esnek" program (çalışma zamanında lambda'yı seçebilirsiniz). Bu, maliyetinin ekstra bir fonksiyon çağrısı ve birçok potansiyel optimizasyonunu kaybetmesiyle ortaya çıkıyor. Ayrıca şunlar vardır

.. yerine kodlanmış kod

Func<Stock, bool> compileTime = (Stock d) => (d.Symbol == "MSFT" && d.CloseDate.Millisecond > 0) || d.Price > 0; 

:

gibi bir şey kullanarak dinamik lambda vs statik lambda karşılaştırabilirsiniz, daha "adil" bir karşılaştırma yapmak için bir fark bulmak, ama biraz daha küçük bir ... Fark aynı sebepten (daha fazla optimizasyon) ... Lambayı el ile optimize ederek farkı azaltabilirsiniz (her zaman mümkün olmasa da, derleyici Bir lambda ile manuel olarak oluşturulamayan geçerli bir CLI kodu oluşturun).

Ama mesela

, aralarından dinamik lambda değiştirirseniz:

var line5 = Expression.OrElse(line4, line3); 

için:

var line5 = Expression.OrElse(line3, line4); 

Sen lambda 1x ve orijinal derlenmiş kod 2x arasında nasıl performans göreceksiniz.

5

Kendimi lambda ifadesi, derlenmiş ifade ağacı, düz işlev çağrısı ve satır içi kodu karşılaştırarak kendimi test ettim. Sonuçlar çok ilginçti. Testimde neredeyse bir hata olduğunu düşünüyorum çünkü ifade ağacı daha hızlıydı ama sanırım bu imkansız değil. Lambda ifadesi en yavaş! İlginç olan, ifade ağacının işlev çağrısından daha hızlı olması ve satır içi koddan biraz daha yavaş olmasıdır. Hiç beklediğim değil.

Düzenleme: Aslında ben 3 ishal için

void TestIt() 
    { 
     var ints = new int[10000000]; 
     Random rand = new Random(); 
     for (int i = 0; i < ints.Length; i++) 
      ints[i] = rand.Next(100); 

     Func<int, int> func1 = i => i + 2; 
     Func<int, int> func2 = CompileIt(); 

     var stopwatch = new Stopwatch(); 

     for (int x = 0; x < 3; x++) 
     { 
      stopwatch.Restart(); 
      for (int i = 0; i < ints.Length; i++) 
       ints[i] = func1(ints[i]); 
      stopwatch.Stop(); 
      Console.Write("Lamba      "); 
      Console.Write(stopwatch.ElapsedMilliseconds); 
      ShowSum(ints); 

      stopwatch.Restart(); 
      for (int i = 0; i < ints.Length; i++) 
       ints[i] = func2(ints[i]); 
      stopwatch.Stop(); 
      Console.Write("Lambda from expression tree "); 
      Console.Write(stopwatch.ElapsedMilliseconds); 
      ShowSum(ints); 

      stopwatch.Restart(); 
      for (int i = 0; i < ints.Length; i++) 
       ints[i] = AddTwo(ints[i]); 
      stopwatch.Stop(); 
      Console.Write("Compiled function   "); 
      Console.Write(stopwatch.ElapsedMilliseconds); 
      ShowSum(ints); 

      stopwatch.Restart(); 
      for (int i = 0; i < ints.Length; i++) 
       ints[i] = ints[i] + 2; 
      stopwatch.Stop(); 
      Console.Write("Compiled code    "); 
      Console.Write(stopwatch.ElapsedMilliseconds); 
      ShowSum(ints); 
     } 
    } 

    private int AddTwo(int value) 
    { 
     return value + 2; 
    } 

    private void ShowSum(int[] ints) 
    { 
     Console.WriteLine(" Sum = " + ints.Sum(i => i).ToString()); 
    } 

    private Func<int, int> CompileIt() 
    { 
     var param1 = Expression.Parameter(typeof(int)); 
     Expression body = Expression.Add(param1, Expression.Constant(2)); 
     return Expression.Lambda<Func<int, int>>(body, new [] { param1 }).Compile(); 
    } 

Sonuçlar aşağıdaki sonuçlara hız eşit olması için lambda ve derlenen fonksiyonu dikkate alacağını şunlardır: Burada

Lamba      164 Sum = 515074919 
Lambda from expression tree 86 Sum = 535074919 
Compiled function   155 Sum = 555074919 
Compiled code    54 Sum = 575074919 

Lamba      153 Sum = 595074919 
Lambda from expression tree 88 Sum = 615074919 
Compiled function   156 Sum = 635074919 
Compiled code    53 Sum = 655074919 

Lamba      156 Sum = 675074919 
Lambda from expression tree 88 Sum = 695074919 
Compiled function   157 Sum = 715074919 
Compiled code    54 Sum = 735074919