28 votos

LazyInitializer vs Perezoso<T> clase. Cuando usar cada uno de ellos

No tengo idea de cuáles son las diferencias entre el LazyInitializer y Lazy<T> la clase. Sé que tanto le inicializar el objeto sólo en la demanda. Cuando tengo que usar cada uno de ellos?

26voto

Jeremy Todd Puntos 2138

No estoy seguro de si aún estás mirando en esto, pero he tenido que profundizar en los detalles de ambos Lazy<T> y LazyInitializer.EnsureInitialized<T>() recientemente, así que pensé que debería compartir mis hallazgos.

En primer lugar, algunos números. Corrí puntos de referencia utilizando ambos métodos en lotes de diez millones de valores de uso de ambos enfoques, el de pruebas para el uso de la memoria con GC.GetTotalMemory(true) y consiguiendo Stopwatch de intervalos para la creación de instancias, el primer valor de acceso, y la posterior valor de accesos:

Lazy<T> Memory Use:                  320,000,000 bytes (32B/instance)
EnsureInitialized<T>() Memory Use:   N/A

Lazy<T> Instantiation Time:          622.01 ms
EnsureInitialized<T>() Inst. Time:   N/A

Lazy<T> First Access:                1,373.50 ms
EnsureInitialized<T>() First Access: 72.94 ms

Lazy<T> Subsequent Accesses:         18.51 ms
EnsureInitialized<T>() Subsequent:   13.75 ms

(Yo usé LazyThreadSafetyMode.PublicationOnly con la Lazy<T>'s, lo que parece ser el mismo hilo de seguridad enfoque adoptado por LazyInitializer de forma predeterminada).

Como se puede ver, a menos que me has jodido mis pruebas de alguna manera (nunca fuera de la cuestión!), bajo estas circunstancias, LazyInitializer es superior en casi todos los cuantificable. No tiene memoria o la creación de instancias de arriba, y es más rápido tanto para crear y recuperar el valor.

Así que, ¿por qué quieres usar Lazy<T>? Bueno, en primer lugar, estos fueron los resultados de la prueba en mi sistema x64, y es posible que usted pueda obtener resultados diferentes en otras circunstancias.

Lazy<T> también puede resultar en la más clara y concisa de código. return myLazy.Value; es mucho más amigable que la de return LazyInitializer.EnsureInitialized(ref myValue, () => GetValue(foo));

Además, Lazy<T> hace las cosas mucho más fácil si usted está tratando con un tipo de valor, o con un tipo de referencia que podría ser legítimamente null. Con LazyInitializer, usted tiene que utilizar un segundo campo booleano para mantener un seguimiento de si el valor ha sido inicializado, lo que agrava el código claridad problema. Lazy<T> también es simple de usar si desea más estrictas de seguridad para subprocesos.

Y en el gran esquema de las cosas, la mayoría de la sobrecarga es probablemente insignificante para un montón de aplicaciones (aunque no siempre, la razón por la que empecé a buscar en esto es debido a que yo estaba trabajando en una aplicación que involucra a millones de pequeños perezosamente cargado de valores, y la de 32 bytes por ejemplo la sobrecarga de Lazy<T> realmente estaba empezando a convertirse en un inconveniente).

En la final, a menos que su aplicación es muy intensivo de la memoria, creo que es usualmente va a ser una cuestión de preferencia personal. Para los no-null a los tipos de referencia, yo personalmente creo LazyInitializer.EnsureInitialized<T>() es un enfoque más elegante, pero puedo cavar el código claridad argumento demasiado.

17voto

sll Puntos 30638

Lazy<T> (MSDN) es un contenedor genérico que permite la creación de una instancia de T en la demanda por la celebración de una T método de fábrica (Func<T>) y llamando al Vaue de la propiedad de captador se accede.

LazyInitializer - estático de la clase con un conjunto de métodos estáticos, esto es sólo un ayudante que utiliza el Activador.CreateInstance() (reflexión) capaz de crear una instancia de un determinado tipo de instancia. No mantener cualquier local de campos privados y no exponer a las propiedades, así que no hay uso de la memoria de los gastos generales.

Cabe señalar que tanto las clases de usos Func<T> como instancia de fábrica.

MSDN dice en pocas palabras acerca de la LazyInitializer clase:

Estas rutinas de evitar la necesidad de asignar un dedicado, perezoso-inicialización de instancia, en lugar de utilizar referencias para asegurar los objetivos han sido inicializado a los que se accede.

PS: Me pareció interesante la manera cómo LazyIntiializer comprueba si la instancia ya inicializado, basta con comparar un pasado en referencia a un default(T), bueno:

private static T EnsureInitializedCore<T>(ref T target, Func<T> valueFactory) 
    where T : class
{
    T t = valueFactory();
    if (t == null)
    {
       throw new InvalidOperationException(Environment.GetResourceString("Lazy_StaticInit_InvalidOperation"));
    }

    Interlocked.CompareExchange<T>(ref target, t, default(T));
    return target;
}

Lo que me parece extraño, se crea una nueva instancia de cada tiempo antes de que un cheque de:

T t = valueFactory(); 
// ... and only then does check

2voto

Lukazoid Puntos 6577

LazyInitializer permite la inicialización perezosa funcionalidad sin la sobrecarga de crear una clase para cada perezosamente inicializado el objeto.

Aquí están los beneficios LazyInitializer puede proporcionar.

Será de acuerdo a sus propios requisitos en cuanto a si la sobrecarga creado por el uso de Lazy<T> es demasiado para la situación.

1voto

Joshua Honig Puntos 5382

La documentación de Inicialización Perezosa lo explica muy claramente. Ver La Inicialización Perezosa. En resumen, Lazy<T> crea una nueva clase (un genérico construido) para cada T que usted use, y una nueva instancia de la clase para cada T instancia que decalre -- incluso si el subyacente T nunca se inicializa. El uso de la estática de los métodos de LazyIntializer puede ser más complejo para la codificación sino que evita la sobrecarga de la Lazy<T> de contenedor de instancias.

0voto

Zhe Puntos 11

Creo que esto responde a tu pregunta: Otra forma de LazyInitialization Sistema.Las operaciones de roscado.ThreadLocal

Es el mismo de la Perezoso, pero la única diferencia es que almacena los datos en el Hilo de base Local. Por lo que los valores en cada Hilo sería una copia diferente de la Inicializa el objeto.

más detalles de: http://www.cshandler.com/2011/09/different-ways-of-lazy-initialization.html

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X