Απόδοση της Object.GetType ()

ψήφοι
38

Έχουμε πολλές κλήσεις υλοτομίας στην εφαρμογή μας. καταγραφικό μας παίρνει μια παράμετρο System.Type έτσι ώστε να μπορεί να δείξει ποια συνιστώσα δημιούργησε την κλήση. Μερικές φορές, όταν μπορούμε να ενοχλούνται, να κάνουμε κάτι σαν:

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

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

Δεδομένου ότι αυτό απαιτεί να πάρει το αντικείμενο τύπου μόνο μία φορά. Ωστόσο, δεν έχουμε καμία πραγματική μετρήσεις σε αυτό. Καθένας πήρε οποιαδήποτε ιδέα πόσο αυτή εξοικονομεί πάνω από την κλήση this.GetType () κάθε φορά που θα συνδεθείτε;

(Συνειδητοποιώ ότι μπορούσα να κάνω τις μετρήσεις τον εαυτό μου χωρίς μεγάλο πρόβλημα, αλλά hey, τι είναι StackOverflow για;)

Δημοσιεύθηκε 09/12/2008 στις 17:20
πηγή χρήστη
Σε άλλες γλώσσες...                            


6 απαντήσεις

ψήφοι
70

Πιστεύω ακράδαντα Υποψιάζομαι ότι gettype () θα πάρει πολύ λιγότερο χρόνο από ό, τι οποιαδήποτε πραγματική καταγραφή. Φυσικά, υπάρχει η πιθανότητα ότι η κλήση σας να Logger.Log δεν θα κάνει καμία πραγματική IO ... εγώ ακόμα υποψιάζομαι η διαφορά θα είναι άνευ σημασίας όμως.

EDIT: Κωδικός Benchmark είναι στο κάτω μέρος. Αποτελέσματα:

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

Αυτό είναι καλώντας την μέθοδο 100 εκατομμύρια φορές - τα κέρδη βελτιστοποίηση μερικά δευτερόλεπτα ή έτσι. Υποψιάζομαι ότι η πραγματική μέθοδος καταγραφής θα έχουν πολύ περισσότερη δουλειά να κάνουμε, και καλώντας ότι 100 εκατομμύρια φορές θα χρειαστεί πολύ περισσότερο από 4 δευτερόλεπτα συνολικά, ακόμα και αν δεν γράφει τίποτα. (Μπορεί να κάνω λάθος, φυσικά - θα έπρεπε να το δοκιμάσω τον εαυτό σας.)

Με άλλα λόγια, ως συνήθως, θα πήγαινα με τον πιο ευανάγνωστο κώδικα και όχι μικρο-βελτιστοποίηση.

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;
    }
}
Απαντήθηκε 09/12/2008 στις 17:45
πηγή χρήστη

ψήφοι
15

Η GetType()λειτουργία επισημαίνεται με το ειδικό γνώρισμα [MethodImpl(MethodImplOptions.InternalCall)]. Αυτό σημαίνει μέθοδος σώμα του δεν περιέχει IL αλλά αντ 'αυτού είναι ένα άγκιστρο μέσα στα εσωτερικά του .NET CLR. Σε αυτή την περίπτωση, φαίνεται στο δυαδικό δομή των μεταδεδομένων του αντικειμένου και κατασκευάζει ένα System.Typeαντικείμενο γύρω από αυτό.

EDIT: Υποθέτω ότι ήταν λάθος για κάτι ...

Είπα ότι: «επειδή GetType()απαιτεί ένα νέο αντικείμενο που θα χτίσει», αλλά φαίνεται ότι αυτό δεν είναι σωστό. Κατά κάποιο τρόπο, η CLR αποθηκεύει προσωρινά το Typeκαι επιστρέφει πάντα το ίδιο αντικείμενο, ώστε να μην χρειάζεται να οικοδομήσουμε ένα νέο αντικείμενο τύπου.

Είμαι με βάση την ακόλουθη δοκιμή:

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

Έτσι, δεν περιμένουμε πολλά κέρδη στην εφαρμογή σας.

Απαντήθηκε 09/12/2008 στις 17:46
πηγή χρήστη

ψήφοι
7

Αμφιβάλλω θα έχετε την ευκαιρία να πάρετε μια ικανοποιητική απάντηση από SO για το θέμα αυτό. Ο λόγος είναι ότι οι επιδόσεις, ιδιαίτερα σενάρια του τύπου αυτού, είναι πολύ συγκεκριμένη εφαρμογή.

Κάποιος μπορεί μετά πίσω με μια γρήγορη χρονόμετρο παράδειγμα της οποίας θα είναι ταχύτερη από την άποψη των πρώτων χιλιοστά του δευτερολέπτου. Αλλά ειλικρινά αυτό δεν σημαίνει τίποτα για την εφαρμογή σας. Γιατί; Εξαρτάται σε μεγάλο βαθμό από τον τρόπο χρήσης γύρω από το συγκεκριμένο σενάριο. Για παράδειγμα ...

  1. Πόσα είδη έχετε;
  2. Πόσο μεγάλο θα είναι οι μέθοδοι;
  3. Μην το κάνετε αυτό για κάθε μέθοδο, ή μόνο μεγάλες επιχειρήσεις;

Αυτά είναι μόνο μερικά από τα ερωτήματα που θα αλλάξει σε μεγάλο βαθμό τη σημασία μιας ευθείας χρόνου αναφοράς.

Απαντήθηκε 09/12/2008 στις 17:46
πηγή χρήστη

ψήφοι
2

Η διαφορά είναι μάλλον αμελητέα όσον αφορά την απόδοση των εφαρμογών. Αλλά η πρώτη προσέγγιση, όπου μπορείτε cache του είδους θα πρέπει να είναι ταχύτερη. Ας πάμε και δοκιμών.

Αυτός ο κωδικός θα σας δείξει τη διαφορά:

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) {
        }
    }
}

Την μηχανή μου, αυτό έδωσε αποτελέσματα της περ. 1500 χιλιοστά του δευτερολέπτου για την πρώτη προσέγγιση και περ. 2200 χιλιοστά του δευτερολέπτου για το δεύτερο.

(Κωδικός και χρονισμούς διορθωθεί - doh!)

Απαντήθηκε 09/12/2008 στις 17:47
πηγή χρήστη

ψήφοι
0

Έχετε σκεφτεί τη χρήση nameof επιχειρηματία;

Απαντήθηκε 11/09/2017 στις 06:42
πηγή χρήστη

ψήφοι
0

χρησιμοποιώντας το πεδίο είναι ο καλύτερος τρόπος και αποφύγετε την εσωτερική ασφάλεια λεξικό προκαλώντας με typeof () και gettype () για να κρατήσει μοναδική αναφορά.

Απαντήθηκε 30/12/2014 στις 14:45
πηγή χρήστη

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