Derlenmiş C # Lambda İfadeleri Performansı


91

Bir koleksiyon üzerinde aşağıdaki basit manipülasyonu 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 İfadeleri kullanalım. Aşağıdaki kod kabaca eşdeğerdir:

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 ifadeyi anında oluşturmak istiyorum, işte 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 tam olarak yukarıdakine benzemiyor, bu yüzden adil olmak gerekirse, ilkini biraz değiştiriyorum:

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 MAX = 100000, VS2008, hata ayıklama AÇIK için sonuçlar geliyor:

Using lambda compiled: 23437500
Using lambda:           1250000
Using lambda combined:  1406250

Ve hata ayıklama KAPALI iken:

Using lambda compiled: 21718750
Using lambda:            937500
Using lambda combined:  1093750

Sürpriz . Derlenen ifade, diğer alternatiflerden yaklaşık 17 kat daha yavaştır. Şimdi sorular geliyor:

  1. Eşdeğer olmayan ifadeleri karşılaştırıyor muyum?
  2. .NET'i derlenmiş ifadeyi "optimize" edecek bir mekanizma var mı?
  3. Aynı zincir çağrısını l.Where(i => i % 2 == 0).Where(i => i > 5);programlı olarak nasıl ifade ederim ?

Biraz daha istatistik. Visual Studio 2010, hata ayıklama AÇIK, optimizasyonlar KAPALI:

Using lambda:           1093974
Using lambda compiled: 15315636
Using lambda combined:   781410

Hata ayıklama AÇIK, optimizasyonlar AÇIK:

Using lambda:            781305
Using lambda compiled: 15469839
Using lambda combined:   468783

Hata ayıklama KAPALI, optimizasyonlar AÇIK:

Using lambda:            625020
Using lambda compiled: 14687970
Using lambda combined:   468765

Yeni Sürpriz. VS2008'den (C # 3) VS2010'a (C # 4) geçiş, UsingLambdaCombinedyerel lambdadan daha hızlı hale getirir .


Tamam, lambda derlenmiş performansını bir büyüklük sırasından daha fazla iyileştirmenin bir yolunu buldum. İşte bir ipucu; profil oluşturucuyu çalıştırdıktan sonra, zamanın% 92'si şunlara harcanır:

System.Reflection.Emit.DynamicMethod.CreateDelegate(class System.Type, object)

Hmmmm ... Neden her yinelemede yeni bir delege yaratıyor? Emin değilim, ancak çözüm ayrı bir yazıda takip ediyor.


3
Bu zamanlamalar Visual Studio'da çalışıyor mu? Öyleyse, bir Yayın modu derlemesini kullanarak zamanlamaları tekrarlayın ve hata ayıklama olmadan çalıştırın (yani, Visual Studio'da Ctrl + F5 veya komut satırından). Ayrıca, Stopwatchzamanlamalar için kullanmak yerine kullanmayı düşünün DateTime.Now.
Jim Mischel

12
Neden daha yavaş olduğunu bilmiyorum ama kıyaslama tekniğiniz pek iyi değil. İlk olarak, DateTime.Now yalnızca saniyenin 1 / 64'ü kadar doğrudur, bu nedenle ölçüm yuvarlama hatanız büyüktür. Bunun yerine Kronometre'yi kullanın; birkaç nanosaniye için doğrudur. İkinci olarak, hem kodu sarsmak için (ilk çağrı) hem de sonraki her çağrıyı ölçüyorsunuz; ortalamaları düşürebilir. (Bu durumda yüz binlik bir MAX muhtemelen sarsıntı yükünü ortalamak için yeterli olsa da, yine de ortalamaya dahil etmek kötü bir uygulamadır.)
Eric Lippert

7
@Eric, yuvarlama hatası ancak her işlemde DateTime.Now.Ticks kullanılıyorsa, başlangıçtan önce ve bitişten sonra milisaniye sayıları performans farkını gösterecek kadar yüksekse olabilir.
Akash Kava

1
Kronometre kullanıyorsanız, doğru sonuçları garantilemek için bu makaleyi takip etmenizi
Zach Green

1
@Eric, bunun mevcut en hassas ölçüm tekniği olmadığını kabul etsem de, bir farklılık büyüklüğünden bahsediyoruz. MAX, önemli sapmaları azaltacak kadar yüksektir.
Hugo Sereno Ferreira

Yanıtlar:


43

İç lambdalar derlenmemiş olabilir mi?!? İşte bir kavram 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

Vay be! Sadece hızlı değil, aynı zamanda doğal lambdadan da daha hızlı. ( Çizik kafası ).


Elbette yukarıdaki kod yazmak için çok zahmetli. Hadi biraz basit sihir yapalım:

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, Optimizasyonlar AÇIK, Hata Ayıklama KAPALI:

Using lambda:                            781260
Using lambda compiled:                 14687970
Using lambda combined:                   468756
Using lambda compiled with MethodCall:   468756
Using lambda compiled constant:          468756

Şimdi tüm ifadeyi dinamik olarak oluşturmadığımı iddia edebilirsiniz; sadece zincirleme çağrılar. Ancak yukarıdaki örnekte tüm ifadeyi oluşturuyorum. Ve zamanlamalar uyuyor. Bu, daha az kod yazmak için bir kısayol.


Anladığım kadarıyla, .Compile () yönteminin derlemeleri iç lambdalara ve dolayısıyla CreateDelegate. Ancak bunu gerçekten anlamak için, bir .NET guru'nun olup biten iç şeyler hakkında biraz yorum yapmasını isterim.

Ve neden , oh neden bu şimdi yerli lambdadan daha hızlı !?


1
En çok oy alan cevap olduğu için kendi cevabımı kabul etmeyi düşünüyorum. Biraz daha beklemeli miyim?
Hugo Sereno Ferreira

Yerel lambda'dan daha hızlı kod alırken ne olacağı hakkında, mikro karşılaştırmalarla ilgili bu sayfaya bir göz atmak isteyebilirsiniz (gerçekten Java'ya özgü hiçbir şey yoktur, adı ne olursa olsun): code.google.com/p/caliper/wiki / JavaMicrobenchmarks
Blaisorblade

Dinamik olarak derlenen lambda'nın neden daha hızlı olduğuna gelince, ilk çalıştırılan "lambda kullanmak" ın bazı kod JIT zorunluluğuyla cezalandırıldığından şüpheleniyorum.
Oskar Berggren

Ne olduğunu bilmiyorum, bir kez derlenmiş ifadeyi test ettiğimde ve alanları ve özellikleri ayarlamak ve almak için elegate oluşturduğumda, oluşturulanelegate özellikler için çok daha hızlıydı, ancak derleme alanlar için çok biraz daha hızlıydı
nawfal

10

Geçenlerde neredeyse aynı soruyu sordum:

Temsilciye Derlenen İfade Performansı

Benim için çözüm Ben buna gerektiğiydi Compileüzerinde Expressionberaber aramaya gerektiğini CompileToMethodÜzerinde ve derlemek Expressiona staticmontaj bir dinamikle yöntemle.

Şöyle:

var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
  new AssemblyName("MyAssembly_" + Guid.NewGuid().ToString("N")), 
  AssemblyBuilderAccess.Run);

var moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");

var typeBuilder = moduleBuilder.DefineType("MyType_" + Guid.NewGuid().ToString("N"), 
  TypeAttributes.Public));

var methodBuilder = typeBuilder.DefineMethod("MyMethod", 
  MethodAttributes.Public | MethodAttributes.Static);

expression.CompileToMethod(methodBuilder);

var resultingType = typeBuilder.CreateType();

var function = Delegate.CreateDelegate(expression.Type,
  resultingType.GetMethod("MyMethod"));

Ancak ideal değil. Bunun tam olarak uygulanacağı türleri oldukça emin değilim ama temsilci tarafından delege tarafından parametreleri olarak alınan veya döndürülen türleri olduğunu düşünüyorum var olmaya publicve genel olmayan. Genel olmayan türler olması gerekir çünkü genel türler System.__Canon, .NET tarafından genel türler için kullanılan bir iç tür olan erişime sahiptir ve bu, "bir publictür olmalı kuralını ihlal eder ).

Bu türler için, görünüşte daha yavaş olanı kullanabilirsiniz Compile. Onları şu şekilde tespit ediyorum:

private static bool IsPublicType(Type t)
{

  if ((!t.IsPublic && !t.IsNestedPublic) || t.IsGenericType)
  {
    return false;
  }

  int lastIndex = t.FullName.LastIndexOf('+');

  if (lastIndex > 0)
  {
    var containgTypeName = t.FullName.Substring(0, lastIndex);

    var containingType = Type.GetType(containgTypeName + "," + t.Assembly);

    if (containingType != null)
    {
      return containingType.IsPublic;
    }

    return false;
  }
  else
  {
    return t.IsPublic;
  }
}

Ama dediğim gibi, bu ideal değil ve yine de bir yöntemi dinamik bir montajda derlemenin neden bazen daha hızlı olduğunu bilmek istiyorum . Bazen şunu söylüyorum, çünkü Expressionderlenenlerin Compilenormal bir yöntem kadar hızlı olduğu durumlar da gördüm . Bunun için soruma bakın.

Ya da birisi publicdinamik derlemeyle "tür olmayan yok " kısıtlamasını atlamanın bir yolunu biliyorsa , bu da hoş karşılanır.


4

İfadeleriniz eşdeğer değildir ve bu nedenle çarpık sonuçlar alırsınız. Bunu test etmek için bir test tezgahı yazdım. Testler, normal lambda çağrısını, eşdeğer derlenmiş ifadeyi, el yapımı eşdeğer bir derlenmiş ifadeyi ve ayrıca oluşturulmuş sürümleri içerir. Bunlar daha doğru sayılar olmalıdır. İlginç bir şekilde, düz ve derlenmiş versiyonlar arasında çok fazla farklılık görmüyorum. Ve derlenen ifadeler doğal olarak daha yavaştır, ancak çok azdır. İyi sayılar elde etmek için yeterince büyük bir girdi ve yineleme sayısına ihtiyacınız var. Fark yaratır.

İkinci sorunuza gelince, bundan nasıl daha fazla performans elde edebileceğinizi bilmiyorum, bu yüzden size yardımcı olamam. Olacağı kadar iyi görünüyor.

HandMadeLambdaExpression()Yöntemde üçüncü sorunuza cevabımı bulacaksınız . Uzantı yöntemleri nedeniyle oluşturulacak en kolay ifade değil, yapılabilir.

using System;
using System.Collections.Generic;
using System.Linq;

using System.Diagnostics;
using System.Linq.Expressions;

namespace ExpressionBench
{
    class Program
    {
        static void Main(string[] args)
        {
            var values = Enumerable.Range(0, 5000);
            var lambda = GetLambda();
            var lambdaExpression = GetLambdaExpression().Compile();
            var handMadeLambdaExpression = GetHandMadeLambdaExpression().Compile();
            var composed = GetComposed();
            var composedExpression = GetComposedExpression().Compile();
            var handMadeComposedExpression = GetHandMadeComposedExpression().Compile();

            DoTest("Lambda", values, lambda);
            DoTest("Lambda Expression", values, lambdaExpression);
            DoTest("Hand Made Lambda Expression", values, handMadeLambdaExpression);
            Console.WriteLine();
            DoTest("Composed", values, composed);
            DoTest("Composed Expression", values, composedExpression);
            DoTest("Hand Made Composed Expression", values, handMadeComposedExpression);
        }

        static void DoTest<TInput, TOutput>(string name, TInput sequence, Func<TInput, TOutput> operation, int count = 1000000)
        {
            for (int _ = 0; _ < 1000; _++)
                operation(sequence);
            var sw = Stopwatch.StartNew();
            for (int _ = 0; _ < count; _++)
                operation(sequence);
            sw.Stop();
            Console.WriteLine("{0}:", name);
            Console.WriteLine("  Elapsed: {0,10} {1,10} (ms)", sw.ElapsedTicks, sw.ElapsedMilliseconds);
            Console.WriteLine("  Average: {0,10} {1,10} (ms)", decimal.Divide(sw.ElapsedTicks, count), decimal.Divide(sw.ElapsedMilliseconds, count));
        }

        static Func<IEnumerable<int>, IList<int>> GetLambda()
        {
            return v => v.Where(i => i % 2 == 0).Where(i => i > 5).ToList();
        }

        static Expression<Func<IEnumerable<int>, IList<int>>> GetLambdaExpression()
        {
            return v => v.Where(i => i % 2 == 0).Where(i => i > 5).ToList();
        }

        static Expression<Func<IEnumerable<int>, IList<int>>> GetHandMadeLambdaExpression()
        {
            var enumerableMethods = typeof(Enumerable).GetMethods();
            var whereMethod = enumerableMethods
                .Where(m => m.Name == "Where")
                .Select(m => m.MakeGenericMethod(typeof(int)))
                .Where(m => m.GetParameters()[1].ParameterType == typeof(Func<int, bool>))
                .Single();
            var toListMethod = enumerableMethods
                .Where(m => m.Name == "ToList")
                .Select(m => m.MakeGenericMethod(typeof(int)))
                .Single();

            // helpers to create the static method call expressions
            Func<Expression, ParameterExpression, Func<ParameterExpression, Expression>, Expression> WhereExpression =
                (instance, param, body) => Expression.Call(whereMethod, instance, Expression.Lambda(body(param), param));
            Func<Expression, Expression> ToListExpression =
                instance => Expression.Call(toListMethod, instance);

            //return v => v.Where(i => i % 2 == 0).Where(i => i > 5).ToList();
            var exprParam = Expression.Parameter(typeof(IEnumerable<int>), "v");
            var expr0 = WhereExpression(exprParam,
                Expression.Parameter(typeof(int), "i"),
                i => Expression.Equal(Expression.Modulo(i, Expression.Constant(2)), Expression.Constant(0)));
            var expr1 = WhereExpression(expr0,
                Expression.Parameter(typeof(int), "i"),
                i => Expression.GreaterThan(i, Expression.Constant(5)));
            var exprBody = ToListExpression(expr1);
            return Expression.Lambda<Func<IEnumerable<int>, IList<int>>>(exprBody, exprParam);
        }

        static Func<IEnumerable<int>, IList<int>> GetComposed()
        {
            Func<IEnumerable<int>, IEnumerable<int>> composed0 =
                v => v.Where(i => i % 2 == 0);
            Func<IEnumerable<int>, IEnumerable<int>> composed1 =
                v => v.Where(i => i > 5);
            Func<IEnumerable<int>, IList<int>> composed2 =
                v => v.ToList();
            return v => composed2(composed1(composed0(v)));
        }

        static Expression<Func<IEnumerable<int>, IList<int>>> GetComposedExpression()
        {
            Expression<Func<IEnumerable<int>, IEnumerable<int>>> composed0 =
                v => v.Where(i => i % 2 == 0);
            Expression<Func<IEnumerable<int>, IEnumerable<int>>> composed1 =
                v => v.Where(i => i > 5);
            Expression<Func<IEnumerable<int>, IList<int>>> composed2 =
                v => v.ToList();
            var exprParam = Expression.Parameter(typeof(IEnumerable<int>), "v");
            var exprBody = Expression.Invoke(composed2, Expression.Invoke(composed1, Expression.Invoke(composed0, exprParam)));
            return Expression.Lambda<Func<IEnumerable<int>, IList<int>>>(exprBody, exprParam);
        }

        static Expression<Func<IEnumerable<int>, IList<int>>> GetHandMadeComposedExpression()
        {
            var enumerableMethods = typeof(Enumerable).GetMethods();
            var whereMethod = enumerableMethods
                .Where(m => m.Name == "Where")
                .Select(m => m.MakeGenericMethod(typeof(int)))
                .Where(m => m.GetParameters()[1].ParameterType == typeof(Func<int, bool>))
                .Single();
            var toListMethod = enumerableMethods
                .Where(m => m.Name == "ToList")
                .Select(m => m.MakeGenericMethod(typeof(int)))
                .Single();

            Func<ParameterExpression, Func<ParameterExpression, Expression>, Expression> LambdaExpression =
                (param, body) => Expression.Lambda(body(param), param);
            Func<Expression, ParameterExpression, Func<ParameterExpression, Expression>, Expression> WhereExpression =
                (instance, param, body) => Expression.Call(whereMethod, instance, Expression.Lambda(body(param), param));
            Func<Expression, Expression> ToListExpression =
                instance => Expression.Call(toListMethod, instance);

            var composed0 = LambdaExpression(Expression.Parameter(typeof(IEnumerable<int>), "v"),
                v => WhereExpression(
                    v,
                    Expression.Parameter(typeof(int), "i"),
                    i => Expression.Equal(Expression.Modulo(i, Expression.Constant(2)), Expression.Constant(0))));
            var composed1 = LambdaExpression(Expression.Parameter(typeof(IEnumerable<int>), "v"),
                v => WhereExpression(
                    v,
                    Expression.Parameter(typeof(int), "i"),
                    i => Expression.GreaterThan(i, Expression.Constant(5))));
            var composed2 = LambdaExpression(Expression.Parameter(typeof(IEnumerable<int>), "v"),
                v => ToListExpression(v));

            var exprParam = Expression.Parameter(typeof(IEnumerable<int>), "v");
            var exprBody = Expression.Invoke(composed2, Expression.Invoke(composed1, Expression.Invoke(composed0, exprParam)));
            return Expression.Lambda<Func<IEnumerable<int>, IList<int>>>(exprBody, exprParam);
        }
    }
}

Ve makinemdeki sonuçlar:

Lambda:
  Geçen: 340971948 123230 (ms)
  Ortalama: 340,971948 0,12323 (ms)
Lambda İfadesi:
  Geçen: 357077202 129051 (ms)
  Ortalama: 357,077202 0,129051 (ms)
El Yapımı Lambda İfadesi:
  Geçen: 345029281 124696 (ms)
  Ortalama: 345,029281 0,124696 (ms)

Oluşturulan:
  Geçen: 340409238 123027 (ms)
  Ortalama: 340,409238 0,123027 (ms)
Oluşturulan İfade:
  Geçen: 350800599 126782 (ms)
  Ortalama: 350.800599 0.126782 (ms)
El Yapımı Oluşturulan İfade:
  Geçen: 352811359 127509 (ms)
  Ortalama: 352,811359 0,127509 (ms)

3

Temsilciler üzerinden derlenen lambda performansı daha yavaş olabilir, çünkü çalışma zamanında derlenen kod optimize edilemeyebilir, ancak manuel olarak yazdığınız ve C # derleyicisi aracılığıyla derlenen kod optimize edilmiştir.

İkinci olarak, birden çok lambda ifadesi birden çok anonim yöntem anlamına gelir ve her birini çağırmak, düz bir yöntemi değerlendirmek için biraz fazla zaman alır. Örneğin, arama

Console.WriteLine(x);

ve

Action x => Console.WriteLine(x);
x(); // this means two different calls..

farklıdır ve ikincisi ile derleyicinin bakış açısından biraz daha fazla ek yük gerekir, aslında iki farklı çağrıdır. Önce x'in kendisini ve sonra bu x'in ifadesini çağıran.

Dolayısıyla, kombine Lambda'nız kesinlikle tek lambda ifadesine göre biraz yavaş performansa sahip olacaktır.

Ve bu, içeride neyin yürütüldüğünden bağımsızdır, çünkü hala doğru mantığı değerlendiriyorsunuz, ancak derleyicinin gerçekleştirmesi için ek adımlar ekliyorsunuz.

İfade ağacı derlendikten sonra bile optimizasyona sahip olmayacak ve yine de küçük karmaşık yapısını koruyacak, onu değerlendirecek ve çağıracak ekstra doğrulama, boş kontrol vb. Olabilir ve bu da derlenmiş lambda ifadelerinin performansını yavaşlatabilir.


2
Yakından bakarsanız, UsingLambdaCombinedtest birden fazla lambda işlevini birleştiriyor ve performansı buna çok yakın UsingLambda. Optimizasyonlarla ilgili olarak, JIT motoru tarafından işlendiklerine ve bu nedenle çalışma zamanında üretilen kodun (derlemeden sonra) herhangi bir JIT optimizasyonunun hedefi olacağına ikna oldum.
Hugo Sereno Ferreira

1
JIT optimizasyonu ve derleme zamanı optimizasyonu, proje ayarlarında derleme zamanı optimizasyonunu kapatabileceğiniz iki farklı şeydir. İkinci olarak, ifade derlemesi muhtemelen dinamik MSIL yayacaktır, bu da mantığı ve işlem sırası ihtiyaçlara göre boş kontroller ve geçerlilik içerdiğinden biraz daha yavaş olacaktır. Reflektöre nasıl derlendiğine bakabilirsiniz.
Akash Kava

2
Düşünceleriniz sağlam olsa da, bu özel sorun hakkında sizinle aynı fikirde olmamalıyım (yani, büyüklük farkının sırası statik derlemeden kaynaklanmamaktadır). Birincisi, çünkü derleme zamanı optimizasyonlarını gerçekten devre dışı bırakırsanız, fark yine de büyüktür. İkincisi, çünkü dinamik üretimi çok az daha yavaş olacak şekilde optimize etmenin bir yolunu zaten buldum. "Neden" i anlamaya çalışayım ve sonuçları göndereyim.
Hugo Sereno Ferreira
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.