Object.GetType Performansı ()

oy
38

Bizim app günlük aramaların çok var. o çağrıyı yarattı hangi bileşenin gösterebilir böylece Bizim logger System.Type parametre alır. biz rahatsız olabilir Bazen biz böyle bir şey yapmak:

class Foo
{
  private static readonly Type myType = typeof(Foo);

  void SomeMethod()
  {
     Logger.Log(myType, SomeMethod started...);
  }
 }

Bu sadece bir defa Tür nesne alma gerektirdiği. Ancak bu konuda herhangi bir fiili ölçümleri yok. Herkes bu biz log this.GetType () her zaman çağırarak üzerinde tasarruf ne kadar herhangi bir fikrin var mı?

(Ben hiçbir büyük sorunu olan ölçüm sağlarken kendim yapabileceğini fark, ama hey, için StackOverflow nedir?)

Oluştur 09/12/2008 saat 17:20
kaynak kullanıcı
Diğer dillerde...                            


7 cevaplar

oy
70

Şiddetle GetType () Herhangi bir fiili günlük çok daha az zaman alacaktır şüpheleniyoruz. Tabii ki, Logger.Log için çağrı herhangi fiili IO yapmayacağım ihtimal ... Ben hala fark olsa alakasız olacak şüpheli.

DÜZENLEME: Benchmark kod alt kısmında bulunmaktadır. Sonuçlar:

typeof(Test): 2756ms
TestType (field): 1175ms
test.GetType(): 3734ms

Yani yöntemini 100 aradığını milyon kez - optimizasyon kazançları birkaç saniye ya da öylesine. Gerçek ölçümleme yöntemi yapılacak çok fazla iş olacak şüpheli ve hiçbir şey yazmaz bile 100 milyon kere toplam 4 saniyeden daha çok uzun süreceğini çağıran. (Tabii, yanlış olabilir - Kendine denemek gerekir.)

Başka bir deyişle, normal, ben en okunabilir kod ziyade mikro optimize ile gitmek istiyorum.

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

class Test
{
    const int Iterations = 100000000;

    private static readonly Type TestType = typeof(Test);

    static void Main()
    {
        int total = 0;
        // Make sure it's JIT-compiled
        Log(typeof(Test)); 

        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            total += Log(typeof(Test));
        }
        sw.Stop();
        Console.WriteLine("typeof(Test): {0}ms", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            total += Log(TestType);
        }
        sw.Stop();
        Console.WriteLine("TestType (field): {0}ms", sw.ElapsedMilliseconds);

        Test test = new Test();
        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            total += Log(test.GetType());
        }
        sw.Stop();
        Console.WriteLine("test.GetType(): {0}ms", sw.ElapsedMilliseconds);
    }

    // I suspect your real Log method won't be inlined,
    // so let's mimic that here
    [MethodImpl(MethodImplOptions.NoInlining)]
    static int Log(Type type)
    {
        return 1;
    }
}
Cevap 09/12/2008 saat 17:45
kaynak kullanıcı

oy
15

GetType()Fonksiyon özel bir sıfat ile işaretlenir [MethodImpl(MethodImplOptions.InternalCall)]. Bu yerine IL içeren değil, onun yöntem gövdesi .NET CLR iç yapıları bir kanca olduğu anlamına gelir. Bu durumda, nesnenin meta ikili yapının bakar ve bir yapıları System.Typeetrafında nesneyi.

DÜZENLEME: Ben Bir konuda yanılmışım ...

"Çünkü: Ben söyledi GetType()inşa edilecek yeni bir Object gerektiriyor" fakat bu doğru değildir görünüyor. Her nasılsa, CLR önbelleğe Typeve yeni Tip nesnesi oluşturmak gerekmez böylece her zaman aynı nesneyi döndürür.

Ben şu teste dayalı ediyorum:

Object o1 = new Object();
Type t1 = o1.GetType();
Type t2 = o1.GetType();
if (object.ReferenceEquals(t1,t2))
    Console.WriteLine("same reference");

Yani, senin uygulanmasında çok kazanç beklemeyin.

Cevap 09/12/2008 saat 17:46
kaynak kullanıcı

oy
7

Sana bu konuda SO gelen tatmin edici bir cevap almak için gidiyoruz şüpheliyim. bu performansı, bu tip özellikle senaryolar da sebebi, yüksek uygulama özeldir.

Hızlı bir kronometre örnekle geri verebilirsiniz Birisi hangi ham miliseconds açısından daha hızlı olacaktır. Ama açıkçası bu uygulamanız için bir şey ifade etmiyor. Niye ya? Bu söz konusu senaryo etrafında kullanım şekline son derece bağlıdır. Örneğin ...

  1. Kaç çeşit var?
  2. Size yöntemler ne kadar büyük?
  3. Her yöntemde, yoksa yalnızca büyük olanlar için bunu musunuz?

Bunlar sadece büyük ölçüde düz bir zaman kriter alaka değiştirecek sorulardan bir kaçıdır.

Cevap 09/12/2008 saat 17:46
kaynak kullanıcı

oy
2

Fark kadarıyla uygulama performansı söz konusu olduğunda muhtemelen önemsiz. Ama türünü önbelleğe Birinci yaklaşım daha hızlı olmalıdır. Hadi gidip testi yapalım.

Bu kod farkı gösterecektir:

using System;

namespace ConsoleApplicationTest {
    class Program {
        static void Main(string[] args) {

            int loopCount = 100000000;

            System.Diagnostics.Stopwatch timer1 = new System.Diagnostics.Stopwatch();
            timer1.Start();
            Foo foo = new Foo();
            for (int i = 0; i < loopCount; i++) {
                bar.SomeMethod();
            }
            timer1.Stop();
            Console.WriteLine(timer1.ElapsedMilliseconds);

            System.Diagnostics.Stopwatch timer2 = new System.Diagnostics.Stopwatch();
            timer2.Start();
            Bar bar = new Bar();
            for (int i = 0; i < loopCount; i++) {
                foo.SomeMethod();
            }
            timer2.Stop();
            Console.WriteLine(timer2.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }

    public class Bar {
        public void SomeMethod() {
            Logger.Log(this.GetType(), "SomeMethod started...");
        }
    }

    public class Foo {
        private static readonly Type myType = typeof(Foo); 
        public void SomeMethod() { 
            Logger.Log(myType, "SomeMethod started..."); 
        }
    }

    public class Logger {
        public static void Log(Type type, string text) {
        }
    }
}

Benim makinede Bu yaklaşık sonuçlar verdi. Birinci yaklaşımda ve yaklaşık 1500 milisaniye. saniye 2200 milisaniye.

(Kod ve zamanlamaları düzeltilmiş - doh!)

Cevap 09/12/2008 saat 17:47
kaynak kullanıcı

oy
0

Eğer kullanmayı düşündünüz mü NameOf operatörü?

Cevap 11/09/2017 saat 06:42
kaynak kullanıcı

oy
0

alanını kullanarak en iyi yoldur ve benzersiz referansı tutmak için typeof () ve GetType () tarafından neden iç sözlük kilidi kaçının.

Cevap 30/12/2014 saat 14:45
kaynak kullanıcı

oy
-1

Ben çok farklı sonuçlar elde ederler.
Bunun için başka bir projede yeni bir konsol uygulaması oluşturulur ve miras ile bir sınıf kullanılır.

Temiz bir karşılaştırma için, sonuçların çekilme boş döngü yarattı.
Ben (el kullanılacak anahtarlama) bir const ve döngüleri için statik yarattı.
Çok ilginç bir şey happend.

Const kullanırken, boş döngü yavaş olmak, ama tamponlu var testi biraz daha hızlı hale gelir.
Hiçbiri veya tüm testleri etkilemelidir bir değişiklik, sadece 2. etkileyen

100000000: Her test için döngülerini

statik döngüsünü kullanarak:

Object.GetType: 1316
TypeOf (Sınıf): 1589
Tip var: 987
Boş Döngü: 799

Temiz genel bakış:
Object.GetType: 517
TypeOf (Sınıf): 790
Tip var: 188

const döngüsünü kullanarak:

Object.GetType: 1316
TypeOf (Sınıf): 1583
Tip var: 853
Boş Döngü: 1061

Temiz genel bakış:
Object.GetType: 255
TypeOf (Sınıf): 522
Tip var: -208

Bunları birden çok kez koştu ve, ve, 10 kat daha fazla döngüleri ile bazı küçük değişikliklerle sonuçlarını etkileyen arka plan süreçlerinin riskini azaltmak için. Yukarıda bu 2 olarak hemen hemen aynı sonuçlar.

O görünüyor Object.GetType()kadar hızlı 1.5-2 kat typeof(class).
Tamponlu var kadar hızlı 1.5-2 kat görünmektedir Object.GetType().

Birazdan uygulama, bu sadece mikro optimize değildir.
Orada burada küçük şeyler feda varsa, bunlar kolayca% 30 daha hızlı yapılmış büyük bir şey daha yavaş olacaktır.

JaredPar cevap Yine biz burada kanıtlamış olarak, testlerin bu tür, özel uygulama hakkında söylediği için güvenilmez.
El altında koduna görünüşte ilgisiz Tüm oldukça farklı sonuçlar veren testler ve işler, performansını etkileyebilir.

Test:

.NetCore 2.1
namespace ConsoleApp1
{
    class Program
    {
        public const int Cycles = 100000000;
        public static int Cycles2 = 100000000;
        public static QSData TestObject = new QSData();
        public static Type TestObjectType;

        static void Main(string[] args)
        {
            TestObjectType = TestObject.GetType();
            Console.WriteLine("Repeated cycles for each test : " + Cycles.ToString());

            var test1 = TestGetType();
            Console.WriteLine("Object.GetType : " + test1.ToString());
            var test2 = TestTypeOf();
            Console.WriteLine("TypeOf(Class)  : " + test2.ToString());
            var test3 = TestVar();
            Console.WriteLine("Type var       : " + test3.ToString());
            var test4 = TestEmptyLoop();
            Console.WriteLine("Empty Loop     : " + test4.ToString());

            Console.WriteLine("\r\nClean overview:");
            Console.WriteLine("Object.GetType : " + (test1 - test4).ToString());
            Console.WriteLine("TypeOf(Class)  : " + (test2 - test4).ToString());
            Console.WriteLine("Type var       : " + (test3 - test4).ToString());

            Console.WriteLine("\n\rPush a button to exit");
            String input = Console.ReadLine();
        }

        static long TestGetType()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < Cycles; i++)
            {
                Type aType = TestObject.GetType();
            }
            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds;
        }

        static long TestTypeOf()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < Cycles; i++)
            {
                Type aType = typeof(QSData);
            }
            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds;
        }

        static long TestVar()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < Cycles; i++)
            {
                Type aType = TestObjectType;
            }
            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds;
        }

        static long TestEmptyLoop()
        {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < Cycles; i++)
            {
                Type aType;
            }
            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds;
        }
    }
}
Cevap 23/04/2019 saat 03:32
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more