2012-05-14 8 views
13

Estoy creando una biblioteca que estoy probando el rendimiento. En él genero un Dictionary<Type, X> una vez. Los elementos se insertan actualmente en un orden aleatorio. El diccionario permanece sin cambios durante la vida útil de la aplicación.¿Alternativa más rápida que el diccionario <Type, X>?

A continuación, se utiliza con frecuencia para buscar elementos. La búsqueda es uno de los cuellos de botella más grandes en la biblioteca.

Sí, estoy micro-optimizando, pero para aprender. Me pregunto si hay una mejor manera de obtener el rendimiento de búsqueda.

actualización

he utilizado dotTrace para medir el rendimiento. El informe + dotTrace está en la computadora de mi casa, por lo que no tengo el informe aquí (podría haberlo cargado en otro lado).

que utilizan las pruebas que se encuentran aquí: https://github.com/danielpalme/IocPerformance

La definición del diccionario se encuentra aquí: https://github.com/jgauffin/Griffin.Container/blob/master/Source/Griffin.Container/ContainerBase.cs

(I creó el contenedor viernes pasado, no esperar demasiado)

Update2

Performance breakdown

Dictionary.TryGetValue toma totalmente 101ms de Resolve (total 251ms) que es 40,2% si interpreto correctamente los números.

+4

a: ¿Cuántos tipos/pares hay en los datos, b: qué le hace pensar que es un cuello de botella? (es decir, ¿cómo ha medido? ¿podemos ver el código de búsqueda?) –

+2

yc: ¿los llamantes utilizan tipos estáticos (es decir, 'int', etc.) o están utilizando objetos' Tipo' debido a la reflexión? si las personas que llaman conocen los tipos de manera estática, hay algunos trucos que podrían usarse. –

+0

@MarcGravell: podría ampliar un poco esos trucos (respuesta o enlace) ya que es un tema interesante. gracias – mathieu

Respuesta

1

La referencia de rendimiento para los contenedores IoC de Daniel Palme (pero las de los demás, así) es un poco engañoso, puesto que el punto de referencia resuelve gráficos de objetos muy superficial desde el recipiente (aunque demuestran claramente que el rendimiento las diferencias entre los contenedores son grandes). Esto no es realista, porque la mayoría de las aplicaciones (que usan DI adecuadamente) tendrán gráficos de objetos que contienen dosens de objetos. Al hacer esto, solo se debe resolver el objeto raíz, y cuando el contenedor se escribe correctamente, significa que solo tendrá una llamada a Dictionary<T,V>.TryGetValue por solicitud (web) en la mayoría de las situaciones (o como máximo en unas pocas). Debido a esto, el rendimiento de Dictionary<T, V> no es realmente un problema.

creo que la mayor parte del costo de rendimiento de Dictionary<T,V> donde TKey es System.Type, tiene que ver con el costo de rendimiento de generar un código hash para el Type dada. Cada vez que llame al TryGetValue, debe llamarse al Type.GetHashCode(). GetHashCode es virtual (no se puede incluir) y ese método llama a otros 3 métodos virtuales. Al final, se realiza una llamada estática (externa) al RuntimeHelpers.GetHashCode(key).

En otras palabras, usted sería capaz de optimizar el rendimiento en escribir una específica (no genérico) de clase que utiliza el diccionario de Type como una llave y en lugar de llamar Type.GetHashCode() debe llamar RuntimeHelpers.GetHashCode(key).

ACTUALIZACIÓN (05/04/2013):

Unos meses atrás me trató de mejorar el rendimiento del contenedor DI mantengo y yo jugaba con la optimización de la parte diccionario. Escribí mi propio diccionario que directamente llamaba al RuntimeHelpers.GetHashCode(key) (y omití las llamadas virtuales) pero al final el rendimiento gana donde tan pequeño (alrededor del 1% en los puntos de referencia de Palme) que decidí revertir estos cambios de código. Entonces, mi comprensión actual es que el costo de rendimiento real con Dictionary<Type, X> es en realidad todo lo que sucede dentro de RuntimeHelpers.GetHashCode(key).

2

Si el tipo es definido en tiempo de compilación, es posible que intenta poner en práctica esta manera:

static class ValueFor<T> 
{ 
    // you get another field per type T 
    public static X X { get; private set; } 

    internal static SetUpValue(X value) { X = value; } 
} 

acceso Sólo el uso de este.

var myIntX = ValueFor<int>.X; 
+0

Desafortunadamente no. Las asignaciones son creadas por el usuario/dev en tiempo de ejecución (como para todos los contenedores IoC) – jgauffin

Cuestiones relacionadas