visual tag studio rendimiento rapido optimizar muy mejorar mas lento como code acelerar c# .net performance c#-4.0 optimization

c# - tag - Campo vs Propiedad. Optimización del rendimiento



visual studio 2017 mas rapido (5)

Tenga en cuenta que esta pregunta está relacionada solo con el rendimiento. Vamos a omitir las pautas de diseño, la filosofía, la compatibilidad, la portabilidad y todo lo que no esté relacionado con el rendimiento puro. Gracias.

Ahora a la pregunta. Siempre asumí que debido a que C # getters / setters son realmente métodos disfrazados, entonces leer el campo público debe ser más rápido que llamar a un getter.

Entonces para asegurarme de que hice una prueba (el código a continuación). Sin embargo, esta prueba solo produce los resultados esperados (es decir, los campos son más rápidos que los getters al 34% ) si lo ejecuta desde Visual Studio.

Una vez que lo ejecutas desde la línea de comandos, muestra más o menos el mismo tiempo ...

La única explicación podría ser que el CLR realiza una optimización adicional (corríjame si me equivoco aquí).

No creo que en una aplicación real donde esas propiedades se usen de una manera mucho más sofisticada se optimicen de la misma manera.

Ayúdame a demostrar o refutar la idea de que en las propiedades de la vida real son más lentos que los campos.

La pregunta es: ¿cómo debo modificar las clases de prueba para hacer que el CLR cambie el comportamiento para que el campo público supere a los getters? O muéstreme que cualquier propiedad sin lógica interna funcionará igual que un campo (al menos en el getter)

EDITAR: solo estoy hablando de la versión de lanzamiento x64.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.Runtime.InteropServices; namespace PropertyVsField { class Program { static int LEN = 20000000; static void Main(string[] args) { List<A> a = new List<A>(LEN); List<B> b = new List<B>(LEN); Random r = new Random(DateTime.Now.Millisecond); for (int i = 0; i < LEN; i++) { double p = r.NextDouble(); a.Add(new A() { P = p }); b.Add(new B() { P = p }); } Stopwatch sw = new Stopwatch(); double d = 0.0; sw.Restart(); for (int i = 0; i < LEN; i++) { d += a[i].P; } sw.Stop(); Console.WriteLine("auto getter. {0}. {1}.", sw.ElapsedTicks, d); sw.Restart(); for (int i = 0; i < LEN; i++) { d += b[i].P; } sw.Stop(); Console.WriteLine(" field. {0}. {1}.", sw.ElapsedTicks, d); Console.ReadLine(); } } class A { public double P { get; set; } } class B { public double P; } }


La única explicación podría ser que el CLR realiza una optimización adicional (corrígeme si me equivoco aquí).

Sí, se llama inline. Se realiza en el compilador (nivel de código de máquina, es decir, JIT). Como el getter / setter es trivial (es decir, un código muy simple), las llamadas al método se destruyen y el getter / setter se escribe en el código circundante.

Esto no ocurre en el modo de depuración para admitir la depuración (es decir, la capacidad de establecer un punto de interrupción en un getter o setter).

En Visual Studio no hay forma de hacerlo en el depurador. Compile versión, ejecute sin depurador adjunto y obtendrá la optimización completa.

No creo que en una aplicación real donde esas propiedades se usen de una manera mucho más sofisticada se optimicen de la misma manera.

El mundo está lleno de ilusiones que están equivocadas. Se optimizarán ya que todavía son triviales (es decir, código simple, por lo que están en línea).


Cabe señalar que es posible ver el rendimiento "real" en Visual Studio.

  1. Compilar en modo de lanzamiento con optimizaciones habilitadas.
  2. Vaya a Depurar -> Opciones y configuraciones, y desmarque "Suprimir la optimización de JIT en la carga del módulo (solo administrado)".
  3. Opcionalmente, desmarque "Habilitar solo mi código"; de lo contrario, es posible que no pueda ingresar el código.

Ahora el ensamblaje jitted será el mismo incluso con el depurador conectado, lo que le permite intervenir en el desmontaje optimizado si así lo desea. Esto es esencial para entender cómo CLR optimiza el código.


Como otros ya han mencionado, los getters están en línea .

Si quieres evitar la inflación, tienes que

  • reemplace las propiedades automáticas con las manuales:

    class A { private double p; public double P { get { return p; } set { p = value; } } }

  • y decirle al compilador que no inserte el getter (o ambos, si lo desea):

    [MethodImpl(MethodImplOptions.NoInlining)] get { return p; }

Tenga en cuenta que el primer cambio no hace una diferencia en el rendimiento, mientras que el segundo cambio muestra una sobrecarga de llamada de método claro:

Propiedades manuales:

auto getter. 519005. 10000971,0237547. field. 514235. 20001942,0475098.

Sin alineación del captador:

auto getter. 785997. 10000476,0385552. field. 531552. 20000952,077111.


Echa un vistazo a las Propiedades vs Campos - ¿Por qué es importante? (Jonathan Aneja) artículo de blog de uno de los miembros del equipo de VB en MSDN. Describe el argumento de propiedad versus campos y también explica las propiedades triviales de la siguiente manera:

Un argumento que he escuchado sobre el uso de campos sobre propiedades es que "los campos son más rápidos", pero para las propiedades triviales eso no es verdad, ya que el compilador de Just-In-Time (JIT) de CLR alineará el acceso a la propiedad y generará código como eficiente como acceder a un campo directamente.


El JIT se alineará con cualquier método (no solo con un getter) que sus métricas internas determinen será más rápido inlined. Dado que una propiedad estándar es return _Property; se insertará en todos los casos.

La razón por la que está viendo un comportamiento diferente es que en el modo de depuración con un depurador conectado, el JIT tiene una desventaja significativa, para garantizar que cualquier ubicación de pila coincida con lo que cabría esperar del código.

También te estás olvidando de la regla de rendimiento número uno, la prueba supera al pensamiento. Por ejemplo, aunque la ordenación rápida es asintóticamente más rápida que la ordenación por inserción, la clasificación por inserción es realmente más rápida para entradas extremadamente pequeñas.