variable type namespace name c# .net performance

c# - namespace - type gettype system int32



Rendimiento de Object.GetType() (6)

Tenemos muchas llamadas de registro en nuestra aplicación. Nuestro registrador toma un parámetro System.Type para que pueda mostrar qué componente creó la llamada. A veces, cuando nos molestan, hacemos algo como:

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

Como esto requiere obtener el objeto Tipo solo una vez. Sin embargo, no tenemos ninguna métrica real sobre esto. Alguien tiene alguna idea de cuánto ahorra por llamar a this.GetType () cada vez que inicia sesión?

(Me doy cuenta de que podría hacer las métricas sin grandes problemas, pero, ¿para qué sirve StackOverflow?)


Dudo que vayan a obtener una respuesta satisfactoria de SO sobre este tema. La razón es que el rendimiento, especialmente los escenarios de este tipo, son altamente específicos de la aplicación.

Alguien puede publicar con un rápido ejemplo de cronómetro que sería más rápido en términos de milisegundos sin procesar. Pero, francamente, eso no significa nada para su aplicación. ¿Por qué? Depende en gran medida del patrón de uso en ese escenario particular. Por ejemplo ...

  1. ¿Cuántos tipos tienes?
  2. ¿Qué tan grandes son tus métodos?
  3. ¿Haces esto para cada método, o solo para los grandes?

Estas son solo algunas de las preguntas que alterarán en gran medida la relevancia de un punto de referencia en tiempo real.


La función GetType() está marcada con el atributo especial [MethodImpl(MethodImplOptions.InternalCall)] . Esto significa que su cuerpo de método no contiene IL, sino que es un gancho en las partes internas de .NET CLR. En este caso, observa la estructura binaria de los metadatos del objeto y construye un objeto System.Type a su alrededor.

EDITAR: Creo que estaba equivocado sobre algo ...

Dije eso: "porque GetType() requiere que se construya un nuevo objeto", pero parece que esto no es correcto. De alguna manera, el CLR guarda en caché el Type y siempre devuelve el mismo objeto para que no necesite construir un nuevo objeto Tipo.

Estoy basado en la siguiente prueba:

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

Por lo tanto, no espero mucha ganancia en su implementación.


Sospecho fuertemente que GetType () tomará mucho menos tiempo que cualquier registro real. Por supuesto, existe la posibilidad de que su llamada a Logger.Log no haga ningún IO real ... Aun así, sospecho que la diferencia será irrelevante.

EDITAR: El código de referencia está en la parte inferior. Resultados:

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

Eso es llamar al método 100 millones de veces, la optimización gana un par de segundos más o menos. Sospecho que el método de registro real tendrá mucho más trabajo que hacer, y llamar a eso 100 millones de veces tomará mucho más de 4 segundos en total, incluso si no escribe nada. (Podría estar equivocado, por supuesto, tendrías que intentarlo tú mismo).

En otras palabras, como es normal, elegiría el código más legible en lugar de la micro-optimización.

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; } }


La diferencia es probablemente insignificante en lo que respecta al rendimiento de la aplicación. Pero el primer enfoque donde almacena en caché el tipo debe ser más rápido. Vamos a probar.

Este código te mostrará la diferencia:

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

En mi máquina, esto dio resultados de aprox. 1500 milisegundos para el primer acercamiento y aprox. 2200 milisegundos para el segundo.

(código y tiempos corregidos - doh!)


usar el campo es la mejor manera y evita el bloqueo del diccionario interno que causa by typeof () y GetType () para mantener una referencia única.


¿Has considerado utilizar el nombre de operador?