2009-04-21 23 views
59

Recientemente he creado una capa de interfaz para distinguir el DataAccessProvider de nuestra capa de lógica empresarial. Con este enfoque podemos cambiar nuestra elección de DataAccessProvider cuando lo deseemos cambiando los valores en la Web/App.Config. (se pueden dar más detalles si es necesario).Qué tan lento es Reflection

De todos modos, para hacer esto utilizamos la reflexión para llevar a cabo nuestra clase DataProvider en la que podemos trabajar.

/// <summary> 
/// The constructor will create a new provider with the use of reflection. 
/// If the assembly could not be loaded an AssemblyNotFoundException will be thrown. 
/// </summary> 
public DataAccessProviderFactory() 
{ 
    string providerName = ConfigurationManager.AppSettings["DataProvider"]; 
    string providerFactoryName = ConfigurationManager.AppSettings["DataProviderFactory"]; 
    try 
    { 
     activeProvider = Assembly.Load(providerName); 
     activeDataProviderFactory = (IDataProviderFactory)activeProvider.CreateInstance(providerFactoryName); 
    } 
    catch 
    { 
     throw new AssemblyNotFoundException(); 
    } 
} 

Pero ahora me pregunto cómo es la reflexión lenta?

+4

Seguramente sería trivial crear un arnés de prueba para compararlo? – marijne

+2

Si la fábrica es un singleton, entonces Assembly.Load solo se llama una vez? – CVertex

+0

http://stackoverflow.com/questions/25458/how-costly-is-net-reflection?rq=1 – nawfal

Respuesta

72

En la mayoría de los casos: más que suficientemente rápido. Por ejemplo, si está utilizando esto para crear un objeto envoltorio DAL, el tiempo necesario para crear el objeto mediante reflexión será minúsculo en comparación con el tiempo que necesita para conectarse a una red. Así que optimizar esto sería una pérdida de tiempo.

Si está utilizando la reflexión en un bucle estrecho, hay trucos para mejorarla:

  • genéricos (utilizando un envoltorio where T : new() y MakeGenericType)
  • Delegate.CreateDelegate (a un delegado escrito; no funciona para los constructores)
  • Reflection.Emit - duro
  • Expression (como Delegate.CreateDelegate, pero más flexible, y trabaja para los constructores)

Pero para sus propósitos, CreateInstance está perfectamente bien. Quédese con eso y mantenga las cosas simples.


edición: mientras que el punto sobre el rendimiento relativo se mantiene, y si bien lo más importante, "medirlo", sigue siendo, debo aclarar algunos de los anteriores. A veces ... es materia. Mida primero. Sin embargo, si lo encuentra es demasiado lento, es posible que desee ver algo así como FastMember, que hace todo el código Reflection.Emit silenciosamente en segundo plano, para darle una buena API fácil; por ejemplo:

var accessor = TypeAccessor.Create(type); 
List<object> results = new List<object>(); 
foreach(var row in rows) { 
    object obj = accessor.CreateNew(); 
    foreach(var col in cols) { 
     accessor[obj, col.Name] = col.Value; 
    } 
    results.Add(obj); 
} 

que es simple, pero será muy rápido. En el ejemplo específico que menciono sobre un DAL envoltorio, si usted está haciendo esto las porciones, considere algo así como dapper, que a su vez hace todo el código Reflection.Emit en el fondo para darle el más rápido posible, pero fácil de usar API:

int id = 12345; 
var orders = connection.Query<Order>(
    "select top 10 * from Orders where CustomerId = @id order by Id desc", 
    new { id }).ToList(); 
+2

Si alguien quiere ver cómo funciona la reflexión para acceder a los campos (no es demasiado complicado) Ver: http: //sharpanalytics.blogspot.de/2012/08/dynamic-methods-for-accessing-fields.html – SACO

+0

@Marc: \t He estado usando la reflexión para obtener el método, nombre de clase del método actual para registrar el error al intentarlo -captura. básicamente para evitar codificar el nombre de la función al registrar el error. ¿Debo preocuparme? –

+1

@Sangram probablemente no, no –

9
+5

No se sorprenda. El tiempo más largo medido fue de 22 segundos para un millón de iteraciones. 22 * micro * segundos por llamada para el peor de los casos. A menos que esté creando una gran cantidad de estos objetos, realmente no es un gran problema. Por supuesto, si * estás * creando una gran cantidad de estos objetos, entonces podría ser un gran problema, pero como Marc señala, todavía va a ser inundado por la conexión de la base de datos y los tiempos de consulta. No se asuste con artículos "x veces más lentos" a menos que sepa que es crítico para el rendimiento. – itowlson

+0

Acepto, aunque es más lento, para la mayoría de las aplicaciones, la penalización de rendimiento no superará los beneficios de usar Reflection. –

3

Aparte de seguir los enlaces proporcionados en otras respuestas y asegurarse de que no está escribiendo un código "patológicamente malo", entonces la mejor respuesta para mí es probarlo usted mismo.

Solo usted sabe dónde está el cuello de la botella, cuántas veces su código de reflexión será usuario, si el código de reflexión estará en bucles ajustados, etc. Conoce su caso de negocio, cuántos usuarios accederán a su sitio, qué los requisitos de rendimiento son

Sin embargo, dado el fragmento de código que ha mostrado aquí, entonces supongo que la sobrecarga de la reflexión no va a ser un problema enorme.

Las pruebas VS.NET y las características de prueba de rendimiento deberían hacer que la medición del rendimiento de este código sea bastante simple.

Si no usa el reflejo, ¿cómo se verá su código? ¿Qué limitaciones tendrá? Es posible que no pueda vivir con las limitaciones con las que se encuentra si elimina el código de reflexión. Podría valer la pena tratar de diseñar este código sin el reflejo para ver si es posible o si la alternativa es deseable.

5

La reflexión no es tan lenta. La invocación de un método por reflexión es aproximadamente 3 veces más lenta que la forma normal. Eso no es problema si haces esto solo una vez o en situaciones no críticas. Si lo usa 10,000 veces en un método de tiempo crítico, consideraría cambiar la implementación.

+0

Si esto es cierto, realmente me gusta esta afirmación. "Invocar un método por reflexión es aproximadamente 3 veces más lento que de la manera normal". ¿Tienes alguna referencia? –

+0

Si mi publicación tiene aproximadamente 3 años, no puedo recordar de dónde obtuve esta información. – Enyra

+0

Convertí una capa de acceso a datos de FieldInfo y PropertyInfo GetValue SetValue a la expresión compilada. El tiempo que tomó leer 30,000 filas con 40 columnas pasó de 4 segundos a 1 segundo. Sin embargo, en una comparación lado a lado, la reflexión es entre 200 y 250 veces más lenta que una expresión compilada al establecer y obtener valores. – Loathing

16

Es más lento en comparación con el código no reflectivo. Lo importante no es si es lento, pero si es lento donde cuenta. Por ejemplo, si instancia objetos utilizando el reflejo en un entorno web donde la concurencia esperada puede elevarse hasta 10 K, será lento.

De todos modos, es bueno no preocuparse por el rendimiento por adelantado. Si las cosas resultan ser lentas, siempre puede acelerarlas si diseñó las cosas correctamente para que las partes que esperaba podrían necesitar una optimización en el futuro estén localizadas.

Esto se puede comprobar famoso artículo si necesita acelero:

Dynamic... But Fast: The Tale of Three Monkeys, A Wolf and the DynamicMethod and ILGenerator Classes

+1

La URL parece haber cambiado para esto, ahora se puede encontrar en: http://www.codeproject.com/Articles/19513/Dynamic-But- Fast-The-Tale-of-Three-Monkeys-A- Wolf – GrandMasterFlush

0

que estaba haciendo somethign similar hasta que empecé a jugar con la COI. Utilizaría una definición de objeto Spring para especificar el proveedor de datos: ¡SQL, XML o Mock!

+0

Spring.net es bastante capaz de actualizar dependencias en tiempo de ejecución. Si actualiza el archivo de configuración y vuelve a cargar una instancia de fábrica, obtendrá una referencia a la instancia actualizada. (Tenga en cuenta que esto no funciona si carga la configuración desde app.config, solo si usa un archivo XML de primavera separado. – Jacob

2

Pensé que haría una prueba rápida para demostrar cómo se compara la lentitud con el sin.

con la reflexión

  • Instantiating 58 objetos por iteración a través de cada uno de sus atributos y búsqueda de
  • Tiempo total: 52.254 nanosegundos

    while (reader.Read()) { 
        string[] columns = reader.CurrentRecord; 
        CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry(); 
        IEnumerable<PropertyInfo> rawPayFileAttributes = typeof(CdsRawPayfileEntry).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(CustomIndexAttribute))); 
        foreach (var property in rawPayFileAttributes) { 
         int propertyIndex = ((CustomIndexAttribute)property.GetCustomAttribute(typeof(CustomIndexAttribute))).Index; 
         if (propertyIndex < columns.Length) 
          property.SetValue(toReturn, columns[propertyIndex]); 
         else 
          break; 
        } 
    } 
    

Sin reflexión

  • Instanciando 58 objetos mediante la creación de un nuevo objeto
  • Tiempo total: 868 nanosegundos

    while (reader2.Read()) { 
         string[] columns = reader2.CurrentRecord; 
         CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry() { 
          ColumnZero = columns[0], 
          ColumnOne = columns[1], 
          ColumnTwo = columns[2], 
          ColumnThree = columns[3], 
          ColumnFour = columns[4], 
          ColumnFive = columns[5], 
          ColumnSix = columns[6], 
          ColumnSeven = columns[7], 
          ColumnEight = columns[8], 
          ColumnNine = columns[9], 
          ColumnTen = columns[10], 
          ColumnEleven = columns[11], 
          ColumnTwelve = columns[12], 
          ColumnThirteen = columns[13], 
          ColumnFourteen = columns[14], 
          ColumnFifteen = columns[15], 
          ColumnSixteen = columns[16], 
          ColumnSeventeen = columns[17] 
         }; 
        } 
    

Aunque, no del todo justo, ya que el reflejo también tiene que recuperar un atributo específico de cada propiedad 58 * 18 veces además de crear un nuevo objeto a través de la reflexión, pero al menos proporciona cierta perspectiva.

Cuestiones relacionadas