2010-08-03 12 views
11

Básicamente, creo una clase ligera, se pasa en alrededor de 10 parámetros, no cambia estos parámetros, simplemente los almacena localmente cuando está en el constructor.Pase por valor vs Pase por rendimiento de referencia C# .net

Algunos son tipos de referencia (cadenas, clases) otros son tipos de valores (int, bool, enumeraciones).

Mi pregunta es, ¿debo pasar todo esto (excepto mis clases) con la palabra clave 'ref'?

Mi consideración aquí es el rendimiento.

+0

No veo cómo ayuda. Incluso si 'ref' ahorra tiempo de copiar una estructura, no puede mantener' ref's como miembros de la clase, 'ref' solo es útil dentro de un método. – Kobi

+0

posible duplicado de [C# 'ref' palabra clave, rendimiento] (http://stackoverflow.com/questions/900903/c-sharp-ref-keyword-performance) – nawfal

Respuesta

16

Utilice únicamente ref si el método tiene que alterar los parámetros, y estos cambios deben ser pasados ​​al código de llamada. Solo debe optimizar esto si lo ha ejecutado a través de un generador de perfiles y ha determinado que el cuello de botella es, de hecho, el CLR que copia los parámetros del método en la pila.

Tenga en cuenta que CLR está muy optimizado para los métodos de llamada con parámetros, por lo que no creo que este sea el problema.

3

Si la clase solo tiene parámetros, ¿debería usar una estructura?

Quizás esto es de interés?

When to use struct?

6

No. Para los tipos de referencia, ya está aprobando una referencia, no es necesario pasar la referencia por referencia a menos que desee cambiar los puntos de referencia, p. asignarle un nuevo objeto. Para tipos de valor, puede pasar por referencia, pero a menos que tenga un problema de rendimiento, no haría esto. Especialmente si los tipos en cuestión son pequeños (4 bytes o menos), hay poca o ninguna ganancia de rendimiento, posiblemente incluso una penalización.

+1

Tengo entendido que siempre hay una pérdida de rendimiento al pasar tipos de valor por referencia, porque los tipos de valores deben estar enmarcados. Por lo que entiendo (desde el maravilloso C# In Depth, por el igualmente maravilloso @JonSkeet) pasar un tipo de valor como un parámetro de referencia nunca causará un aumento en el rendimiento, por el contrario siempre causará una disminución en el rendimiento. –

+0

@BenH: _ "siempre hay una pérdida de rendimiento al pasar tipos de valor por referencia, porque los tipos de valores deben estar encuadrados" _ - no. parece confundir pasar por referencia al pasar una referencia. Ellos no son los mismos. El uso de 'ref' con un tipo de valor no encapsula el valor. Pasa una referencia (puntero) a la variable que contiene el valor. –

+0

@PeterDuniho: dentro de las partes internas de .NET, pasar un argumento por referencia pasa un "byref". No he visto ese término usado mucho en las discusiones, pero creo que habría menos confusión si se usara más a menudo, ya que suena mucho menos como "referencia de objeto" que la frase "pasar por referencia". – supercat

3

No. Pasar los parámetros por referencia agrega sobrecarga, por lo que solo disminuiría el rendimiento.

+0

Estoy acostumbrado a C++, así que podría estar totalmente equivocado, pero ¿podría elaborar esto más? digamos que tengo un gran objeto, wouldnt: pasar por referencia solo pasar una dirección de los datos en lugar de tener que copiar el objeto completo? –

+0

@SvenvandenBoogaart no lo estás haciendo. Está creando un nuevo puntero dentro del método para mantener el valor del objeto. Pero cambiar el valor del puntero no modificará el puntero externo utilizado para pasar este valor a la llamada al método. –

2

Por lo que tengo entendido, tiene una clase con solo campos y un constructor que está asignando los parámetros a esos campos, ¿verdad?

Si ese es el caso, consideraría usar ref en la mala práctica del constructor. Si asigna el parámetro a un campo en esa clase, se almacena por valor en cualquier caso. Entonces, si no cambia el valor en el constructor, no hay necesidad de usarlo por referencia.

+0

+1 - exactamente lo que no pude articular en mi comentario. – Kobi

3

Encontré en llamadas de función de alto volumen para tipos de mayor valor que pasar por ref era más rápido, levemente. Si tiene un gran volumen de llamadas a función y necesita velocidad, esto podría ser una consideración. Estoy abierto a pruebas alternativas.

public static void PassValue(decimal value) 
{ 

} 

public static void PassRef(ref decimal value) 
{ 

}    

decimal passMe = 0.00010209230982047828903749827394729385792342352345m; 

for (int x = 0; x < 20; x++) 
{ 
    DateTime start = DateTime.UtcNow; 
    TimeSpan taken = new TimeSpan(); 

    for (int i = 0; i < 50000000; i++) 
    { 
     PassValue(passMe); 
    } 

    taken = (DateTime.UtcNow - start); 
    Console.WriteLine("Value : " + taken.TotalMilliseconds); 

    start = DateTime.UtcNow; 

    for (int i = 0; i < 50000000; i++) 
    { 
     PassRef(ref passMe); 
    } 

    taken = (DateTime.UtcNow - start); 
    Console.WriteLine("Ref : " + taken.TotalMilliseconds); 
} 

Resultados:

Value : 150 
Ref : 140 
Value : 150 
Ref : 143 
Value : 151 
Ref : 143 
Value : 152 
Ref : 144 
Value : 152 
Ref : 143 
Value : 154 
Ref : 144 
Value : 152 
Ref : 143 
Value : 154 
Ref : 143 
Value : 157 
Ref : 143 
Value : 153 
Ref : 144 
Value : 154 
Ref : 147 
Value : 153 
Ref : 144 
Value : 153 
Ref : 144 
Value : 153 
Ref : 146 
Value : 152 
Ref : 144 
Value : 153 
Ref : 143 
Value : 153 
Ref : 143 
Value : 153 
Ref : 144 
Value : 153 
Ref : 144 
Value : 152 
Ref : 143 
0

no estoy seguro para C#, sin embargo para C++/C depende de lo que está pasando. Si está pasando un tipo de base (int, float, double, char) ... entonces pasar por el valor es más rápido que pasar por referencia (porque la función de llamada está optimizada para esto. Si está pasando algo más grande, una clase grande , una matriz, una cadena larga ... luego pasar por referencia es mucho, mucho más rápido porque si está haciendo una int [100000], entonces el procesador tendrá que asignar un trozo de 100000 x 32/64 (dependiendo de la arquitectura), y luego copie todos los valores, eso lleva mucho tiempo.Mientras que por referencia solo pasa un puntero

C# abstrae la mayor parte de esto, así que no sé lo que hace, pero creo que lo que se aplica a C++/c en términos de eficiencia generalmente se puede aplicar a C#.

Cuestiones relacionadas