Derlenmiş C# Lambda İfadeleri Performans
Koleksiyonu aşağıdaki basit manipülasyon düşünün:
static List<int> x = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var result = x.Where(i => i % 2 == 0).Where(i => i > 5);
Şimdi gelelim İfadeler kullanın. Aşağıdaki kodu kabaca eşdeğer
static void UsingLambda() {
Func<IEnumerable<int>, IEnumerable<int>> lambda = l => l.Where(i => i % 2 == 0).Where(i => i > 5);
var t0 = DateTime.Now.Ticks;
for (int j = 1; j < MAX; j )
var sss = lambda(x).ToList();
var tn = DateTime.Now.Ticks;
Console.WriteLine("Using lambda: {0}", tn - t0);
}
Ama-the-fly ifade oluşturmak istiyorum, burada yeni bir test:
static void UsingCompiledExpression() {
var f1 = (Expression<Func<IEnumerable<int>, IEnumerable<int>>>)(l => l.Where(i => i % 2 == 0));
var f2 = (Expression<Func<IEnumerable<int>, IEnumerable<int>>>)(l => l.Where(i => i > 5));
var argX = Expression.Parameter(typeof(IEnumerable<int>), "x");
var f3 = Expression.Invoke(f2, Expression.Invoke(f1, argX));
var f = Expression.Lambda<Func<IEnumerable<int>, IEnumerable<int>>>(f3, argX);
var c3 = f.Compile();
var t0 = DateTime.Now.Ticks;
for (int j = 1; j < MAX; j )
var sss = c3(x).ToList();
var tn = DateTime.Now.Ticks;
Console.WriteLine("Using lambda compiled: {0}", tn - t0);
}
Tabii ki aynen yukarıdaki gibi değil, adil olmak gerekirse, ben ilk biraz değiştirin:
static void UsingLambdaCombined() {
Func<IEnumerable<int>, IEnumerable<int>> f1 = l => l.Where(i => i % 2 == 0);
Func<IEnumerable<int>, IEnumerable<int>> f2 = l => l.Where(i => i > 5);
Func<IEnumerable<int>, IEnumerable<int>> lambdaCombined = l => f2(f1(l));
var t0 = DateTime.Now.Ticks;
for (int j = 1; j < MAX; j )
var sss = lambdaCombined(x).ToList();
var tn = DateTime.Now.Ticks;
Console.WriteLine("Using lambda combined: {0}", tn - t0);
}
Şimdi gelir = 100000, VS2008, hata ayıklama için MAX: sonuçları
Using lambda compiled: 23437500
Using lambda: 1250000
Using lambda combined: 1406250
Ve hata ayıklama KAPALI:
Using lambda compiled: 21718750
Using lambda: 937500
Using lambda combined: 1093750
Sürpriz. Derlenmiş ifadesi yaklaşık 17x diğer alternatiflere göre daha yavaştır. Şimdi geliyor soru
- Non-eşdeğer ifadeler karşılaştırma mıyım?
- Bir mekanizma yapmak .NET "optimize" derlenmiş ifadesi?
- Nasıl
l.Where(i => i % 2 == 0).Where(i => i > 5);
programlama yoluyla arayın aynı zincirin ifade ederim?
Biraz daha istatistik. Visual Studio 2010, hata ayıklama, optimizasyon OFF:
Using lambda: 1093974
Using lambda compiled: 15315636
Using lambda combined: 781410
Hata ayıklama, optimizasyon:
Using lambda: 781305
Using lambda compiled: 15469839
Using lambda combined: 468783
KAPALI hata ayıklama, optimizasyon:
Using lambda: 625020
Using lambda compiled: 14687970
Using lambda combined: 468765
Yeni Sürpriz.VS2010 için VS2008 C#3) geçiş (C#4), UsingLambdaCombined
yerli lambda daha hızlı yapar.
Tamam, büyüklükte bir sipariş daha fazla lambda derlenmiş performansını artırmak için bir yol buldum. İşte size bir ipucu; çalıştırdıktan sonra profiler, 92% zaman harcadık
System.Reflection.Emit.DynamicMethod.CreateDelegate(class System.Type, object)
Hmmmm... Neden her tekrarında yeni bir temsilci yaratıyor? Emin değilim ama çözüm ayrı bir yazı aşağıda.
CEVAP
Bu iç Lambda derlenmiş olan değil mi?!? İşte bir kanıtı:
static void UsingCompiledExpressionWithMethodCall() {
var where = typeof(Enumerable).GetMember("Where").First() as System.Reflection.MethodInfo;
where = where.MakeGenericMethod(typeof(int));
var l = Expression.Parameter(typeof(IEnumerable<int>), "l");
var arg0 = Expression.Parameter(typeof(int), "i");
var lambda0 = Expression.Lambda<Func<int, bool>>(
Expression.Equal(Expression.Modulo(arg0, Expression.Constant(2)),
Expression.Constant(0)), arg0).Compile();
var c1 = Expression.Call(where, l, Expression.Constant(lambda0));
var arg1 = Expression.Parameter(typeof(int), "i");
var lambda1 = Expression.Lambda<Func<int, bool>>(Expression.GreaterThan(arg1, Expression.Constant(5)), arg1).Compile();
var c2 = Expression.Call(where, c1, Expression.Constant(lambda1));
var f = Expression.Lambda<Func<IEnumerable<int>, IEnumerable<int>>>(c2, l);
var c3 = f.Compile();
var t0 = DateTime.Now.Ticks;
for (int j = 1; j < MAX; j )
{
var sss = c3(x).ToList();
}
var tn = DateTime.Now.Ticks;
Console.WriteLine("Using lambda compiled with MethodCall: {0}", tn - t0);
}
Ve şimdi zamanlamaları
Using lambda: 625020
Using lambda compiled: 14687970
Using lambda combined: 468765
Using lambda compiled with MethodCall: 468765
Heyo!! Hızlı değil, yerli lambda daha hızlı. (Sıfırdan kafa).
Elbette yukarıdaki kodu sadece çok acı yazmaktır. Hadi bir kaç basit büyü yapmak:
static void UsingCompiledConstantExpressions() {
var f1 = (Func<IEnumerable<int>, IEnumerable<int>>)(l => l.Where(i => i % 2 == 0));
var f2 = (Func<IEnumerable<int>, IEnumerable<int>>)(l => l.Where(i => i > 5));
var argX = Expression.Parameter(typeof(IEnumerable<int>), "x");
var f3 = Expression.Invoke(Expression.Constant(f2), Expression.Invoke(Expression.Constant(f1), argX));
var f = Expression.Lambda<Func<IEnumerable<int>, IEnumerable<int>>>(f3, argX);
var c3 = f.Compile();
var t0 = DateTime.Now.Ticks;
for (int j = 1; j < MAX; j ) {
var sss = c3(x).ToList();
}
var tn = DateTime.Now.Ticks;
Console.WriteLine("Using lambda compiled constant: {0}", tn - t0);
}
Ve bazı zamanlamalar, VS2010, hata Ayıklama KAPALI Optimizasyon:
Using lambda: 781260
Using lambda compiled: 14687970
Using lambda combined: 468756
Using lambda compiled with MethodCall: 468756
Using lambda compiled constant: 468756
Şimdi bütün ifade dinamik olarak oluşturuluyor değilim; sadece zincirleme çağırmaları söyleyebiliriz. Ama yukarıdaki örnekte bütün bir ifade oluşturur. Ve zamanlamaları maç. Bu daha az kod yazmak için sadece bir kısayol.
Neler olduğunu benim anlayış olduğunu .() Derleme yöntemi iç Lambda, ve CreateDelegate
sürekli çağırma böylece derlemeler yaymak değil. Ama gerçekten bunu anlamak için, bir sahip olmak isterdim .NET guru iç şeyler hakkında biraz yorum.
Veneden, ohnedenbu yerel bir lambda şimdi daha hızlı!?
Neden bazı C# ifadeleri statik yönteml...
Kullanarak lambda ifadeleri ile Varlık...
Parametre adı yansıtan: C kötüye lambd...
Kullanamazsınız veya lambda ifadeleri ...
GroupBy, Count kullanarak ve SERİ Topl...