2009-07-22 10 views
48

¿hay alguna manera medible diferencia de rendimiento entreRendimiento de encasillamiento

((TypeA) obj).method1(); 
((TypeA) obj).method2(); 
((TypeA) obj).method3(); 

y

var A = (TypeA) obj; 
A.method1(); 
A.method2(); 
A.method3(); 

cuando se utiliza una gran cantidad de veces?

A menudo veo algo así como

if (((TextBox)sender).Text.Contains('.') || ((TextBox)sender).Text.Contains(',')) 

y se preguntan si esto es una pérdida de rendimiento.

+7

La única manera de responder "hay una diferencia mensurable" es medirla y ver. No hay nada que te impida hacer eso ... –

Respuesta

48

Puede medirse si se realiza miles de millones de veces con muy poco trabajo. No sé si el CLR guardará efectivamente el hecho de que el elenco funcionó, por lo que no tiene que volver a hacerlo; si no lo hace ahora, podría hacerlo en una versión posterior. Podría hacerlo en el JIT de 64 bits pero no en la versión de 32 bits, o viceversa, ya se entiende. Sin embargo, dudo que eso haga una diferencia significativa en el código normal.

Personalmente me gusta la legibilidad de la segunda forma más, sin embargo, y eso es más importante por el momento.

+2

+1 también creo que el encasillado se debe hacer usando el operador "as" y se verificará nulo más adelante, a menos que * quieras * que se genere una excepción. –

+5

Estoy de acuerdo, aunque a menudo veo que se usa "como" cuando se debe usar un yeso *. Muy a menudo "el tipo incorrecto" == "error", en cuyo caso el lanzamiento simple es el camino correcto a seguir. –

+0

En cuanto al rendimiento, el operador "as" hace que el csc emita código de operación "isinst" (frente al código de operación "Castclass" para el estilo de pantano) que es hasta 8 veces más rápido cuando se mide en millones de moldes. –

35

@dkson: He probado ambos métodos. Esto es lo que encontré en mi computadora:

Se refieren al mismo en rendimiento. De hecho, el segundo método me pareció un poco más lento. La razón (creo) es el costo de la variable extra y el lanzamiento inicial. Por supuesto, si usa suficientes yesos, puede recuperar ese costo de rendimiento. Parece que estás a salvo en términos de rendimiento solo después de guardar 20-30 lanzamientos.

Éstos son los resultados de las dos pruebas más recientes:

TestMuliCast\_3x:  00:00:00.5970000 
TestSingleCast\_3x: 00:00:00.6020000 
TestMuliCast\_30x:  00:00:06.0930000 
TestSingleCast\_30x: 00:00:06.0480000 

TestMuliCast\_3x:  00:00:00.6120000 
TestSingleCast\_3x: 00:00:00.6250000 
TestMuliCast\_30x:  00:00:06.5490000 
TestSingleCast\_30x: 00:00:06.4440000 

También he probado la diferencia entre castclass y isinst. Sobre la base de lo que había leído:

http://m3mia.blogspot.com/2007/11/comparing-isinst-to-castclass.html
http://www.codeproject.com/KB/cs/csharpcasts.aspx
http://discuss.joelonsoftware.com/default.asp?dotnet.12.635066.13

pensé isinst sería más rápido que castclass incluso cuando no había excepciones. Sin embargo, después de crear mis propios puntos de referencia, encontré que es ligeramente más lento que castclass. Muy interesante. Aquí están mis resultados:

TestEmptyLoop:  00:00:00.0870000 
TestDCast\_castclass: 00:00:00.2640000 
TestDCast\_isinst:  00:00:00.3780000 

TestEmptyLoop:  00:00:00.0870000 
TestDCast\_castclass: 00:00:00.2600000 
TestDCast\_isinst:  00:00:00.3750000 

Así que, Sr. Skeet, me encuentro en la posición correcta.

Medio Ambiente:

Windows Vista
máxima velocidad Core 3.2Ghz
.NET Framework v2.0.50727

Aquí está el código fuente completo de los puntos de referencia que creó y dirigió: (hace uso de marco Jon Skeets Microbenchmarking disponibles here)

using System; 
using System.Collections; 

public class CastingBenchmark 
{ 
    static Int64 Iterations=100000000; 
    static Int64 TestWork = 0; 

    public static void Init(string[] args) 
    { 
     if (args.Length>0) 
      Iterations = Int64.Parse(args[0]); 
    } 

    public static void Reset() 
    { 
     TestWork = 0; 
    } 

    internal class BaseType { public void TestBaseMethod() { TestWork++; } } 

    internal class DerivedType : BaseType { 
     public void TestDerivedMethod() { TestWork++; } 
     public void TestDerivedMethod2() { TestWork++; } 
     public void TestDerivedMethod3() { TestWork++; } 
} 

[Benchmark] 
public static void TestMuliCast_3x() 
{ 
    BaseType TestBaseType = new DerivedType(); 

    for (int x = 0; x < Iterations; x++) 
    { 
     ((DerivedType)TestBaseType).TestDerivedMethod(); 
     ((DerivedType)TestBaseType).TestDerivedMethod2(); 
     ((DerivedType)TestBaseType).TestDerivedMethod3(); 
    } 
} 

[Benchmark] 
public static void TestSingleCast_3x() 
{ 
    BaseType TestBaseType = new DerivedType(); 

    for (int x = 0; x < Iterations; x++) 
    { 
     DerivedType TestDerivedType = (DerivedType)TestBaseType; 
     TestDerivedType.TestDerivedMethod(); 
     TestDerivedType.TestDerivedMethod2(); 
     TestDerivedType.TestDerivedMethod3(); 
    } 
} 

[Benchmark] 
public static void TestMuliCast_30x() 
{ 
    BaseType TestBaseType = new DerivedType(); 

    for (int x = 0; x < Iterations; x++) 
    { 
     //Simulate 3 x 10 method calls while casting 
     for (int y = 0; y < 10; y++) { 

      ((DerivedType)TestBaseType).TestDerivedMethod(); 
      ((DerivedType)TestBaseType).TestDerivedMethod2(); 
      ((DerivedType)TestBaseType).TestDerivedMethod3(); 
     } 
    } 
} 

[Benchmark] 
public static void TestSingleCast_30x() 
{ 
    BaseType TestBaseType = new DerivedType(); 

    for (int x = 0; x < Iterations; x++) 
    { 
     DerivedType TestDerivedType = (DerivedType)TestBaseType; 

     //Simulate 3 x 10 method calls on already-cast object 
     for (int y = 0; y < 10; y++) 
     { 
      TestDerivedType.TestDerivedMethod(); 
      TestDerivedType.TestDerivedMethod2(); 
      TestDerivedType.TestDerivedMethod3(); 
     } 
    } 
} 

    [Benchmark] 
    public static void TestEmptyLoop() 
    { 
     for (int x = 0; x < Iterations; x++) 
     { 
     } 
    } 

    [Benchmark] 
    public static void TestDCast_castclass() 
    { 
     BaseType TestDerivedType = new DerivedType(); 

     for (int x = 0; x < Iterations; x++) 
     { 
      ((DerivedType)TestDerivedType).TestDerivedMethod(); 
     }  
    } 

    [Benchmark] 
    public static void TestDCast_isinst() 
    { 
     BaseType TestDerivedType = new DerivedType(); 

     for (int x = 0; x < Iterations; x++) 
     { 
      (TestDerivedType as DerivedType).TestDerivedMethod(); 
     } 
    } 
} 

Y la IL resultante para isinst y castclass métodos:

method public hidebysig static void TestDCast_isinst() cil managed 
{ 
    .custom instance void BenchmarkAttribute::.ctor() 
    .maxstack 2 
    .locals init (
     [0] class CastingBenchmark/BaseType TestDerivedType, 
     [1] int32 x) 
    L_0000: newobj instance void CastingBenchmark/DerivedType::.ctor() 
    L_0005: stloc.0 
    L_0006: ldc.i4.0 
    L_0007: stloc.1 
    L_0008: br.s L_0019 
    L_000a: ldloc.0 
    L_000b: isinst CastingBenchmark/DerivedType 
    L_0010: callvirt instance void CastingBenchmark/DerivedType::TestDerivedMethod() 
    L_0015: ldloc.1 
    L_0016: ldc.i4.1 
    L_0017: add 
    L_0018: stloc.1 
    L_0019: ldloc.1 
    L_001a: conv.i8 
    L_001b: ldsfld int64 CastingBenchmark::Iterations 
    L_0020: blt.s L_000a 
    L_0022: ret 
} 

.method public hidebysig static void TestDCast_castclass() cil managed 
{ 
    .custom instance void BenchmarkAttribute::.ctor() 
    .maxstack 2 
    .locals init (
     [0] class CastingBenchmark/BaseType TestDerivedType, 
     [1] int32 x) 
    L_0000: newobj instance void CastingBenchmark/DerivedType::.ctor() 
    L_0005: stloc.0 
    L_0006: ldc.i4.0 
    L_0007: stloc.1 
    L_0008: br.s L_0019 
    L_000a: ldloc.0 
    L_000b: castclass CastingBenchmark/DerivedType 
    L_0010: callvirt instance void CastingBenchmark/DerivedType::TestDerivedMethod() 
    L_0015: ldloc.1 
    L_0016: ldc.i4.1 
    L_0017: add 
    L_0018: stloc.1 
    L_0019: ldloc.1 
    L_001a: conv.i8 
    L_001b: ldsfld int64 CastingBenchmark::Iterations 
    L_0020: blt.s L_000a 
    L_0022: ret 
} 
Cuestiones relacionadas