2012-10-07 40 views
15

¿Por qué los métodos PropertyInfo para obtener y configurar una propiedad son tan lentos? Si construyo un delegado usando Reflection.Emit, es mucho más rápido.¿Por qué PropertyInfo SetValue y GetValue son tan lentos?

¿Están haciendo algo importante para justificar el tiempo que toman? Es decir ... ¿Me falta algo usando Reflection.Emit para crear delegados en lugar de marcar GetValue y SetValue de PropertyInfo (aparte de la velocidad de desarrollo)?

PD: ¡Por favor, den evidencia, no solo adivinen!

+3

FYI, si usted está buscando una manera más fácil de conseguir un aumento de rendimiento de Reflection.Emit, sólo podría Delegate.CreateDelegate con PropertyInfo.GetGetMethod/PropertyInfo.GetSetMethod (y almacenar en caché el delegado por supuesto). – Ani

+0

Tendría que bloquear la instancia del objeto en el delegado. Los métodos 'GetValue' y' SetValue' toman la instancia del objeto, en el momento de la llamada. –

+0

Delegate.CreateDelegate puede crear objetos delegados de instancia abierta y cerrada. – Ani

Respuesta

16

La implementación de RuntimePropertyInfo (que es la subclase concreta de PropertyInfo de tipos en tiempo de ejecución) implementa GetValue y SetValue invocando los métodos get y set a través de la reflexión (MethodInfo.Invoke), mientras que el delegado generada probablemente llamadas directamente los métodos. Por lo tanto, la pregunta se reduce a: ¿por qué es tan lento RuntimeMethodInfo.Invoke en comparación con una invocación compilada?

Cuando descompilar (o mirar las fuentes de referencia para) RuntimeMethodInfo.Invoke, se puede ver que esto es probablemente porque Invoke lleva a cabo una gran cantidad de tareas:

  • que realiza comprobaciones de coherencia (hacer el número y tipos de los parámetros aprobados coinciden con la firma? ¿la instancia aprobada coincide con el tipo de declaración? ¿se pasó una instancia aunque el método es estático?),
  • realiza la visibilidad y (si se evitan los controles de visibilidad) las verificaciones de seguridad
  • la matriz de parámetros, tratando a la referencia rámetros de una manera especial para que puedan ser escritas de nuevo a tarde,
  • que unboxes parámetros si es necesario,
  • que necesita para encontrar el puntero del método basado en el mango mango tipo de tiempo de ejecución y el método asociado con el RuntimeMethodHandle y luego invocar el método,
  • pone el valor de retorno si es necesario, y
  • inserta y coloca en el conjunto de parámetros los parámetros de ref/out.

El tiempo de ejecución realizará comprobaciones de coherencia, seguridad y visibilidad similares cuando compila su delegado en código nativo ejecutable. También emite código para boxeo/unboxing, etc. Sin embargo, solo necesita hacer estas cosas una vez, y puede garantizar que el código sea seguro de ejecutar. Esto hace que el método real llame a una operación muy económica (cargue los parámetros y salte a la dirección del método).

Por el contrario, cada llamada a RuntimeMethodInfo.Invoke (y por tanto a GetValue/SetValue) tiene que repetir todo el trabajo, ya que el contexto - los parámetros, ejemplo, y el uso del tipo de retorno - no se conoce. Y esta es probablemente la razón por la cual es tan lento.

Acerca de lo que puede estar perdiendo: si usted emite sus propios delegados de invocación de propiedad, usted por supuesto necesita lidiar con boxeo/unboxing, ref/out parameters, etc. usted mismo.

10

No es necesario utilizar Emit. Es mucho más fácil usar Expression. Puede acelerar el acceso como se describe en SO. La clase auxiliar crea un "puntero de método" (Acción/Func) para el captador o instalador. Si reutilizas Action/Func, podrás realizar tan rápido como un setter normal.

// creating setter (once) 
    var propertyInfo = typeof(T).GetProperty(field); 
    var setter = FastInvoke.BuildUntypedSetter<T>(propertyInfo)); 

    // usage somehow later in a loop of data 
    foreach(var myobject in MySource) 
    { 
    setter(myobject, myValue) 
    } 
+0

http://stackoverflow.com/questions/1027980/improving-performance-reflection-what-alternatives-should-i-consider –

+0

@ sky-dev: ¿Cuál es su punto? – Fried

+0

@Fried Tu enlace está roto mientras que sky-devs link funciona. Supongo que ese es su punto. – ViRuSTriNiTy

Cuestiones relacionadas