What are the differences between LazyInitializer and Lazy<T> classes? I know they both will initialize the object only on demand. When do I need to use each of them?
Lazy initialization is primarily used to improve performance, avoid wasteful computation, and reduce program memory requirements. These are the most common scenarios: When you have an object that is expensive to create, and the program might not use it.
Using the Lazy<T> class in C# Although you can write your own custom code to implement lazy initialization, Microsoft recommends using the Lazy<T> class instead. The Lazy<T> class in the System namespace in C# was introduced as part of . Net Framework 4.0 to provide a thread-safe way to implement lazy initialization.
The Lazy<T> object ensures that all threads use the same instance of the lazily initialized object and discards the instances that are not used.
In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed. It is a kind of lazy evaluation that refers specifically to the instantiation of objects or other resources.
I'm not sure if you're still looking into this, but I've had to delve into the details of both Lazy<T>
and LazyInitializer.EnsureInitialized<T>()
recently, so I thought I should share my findings.
First, some numbers. I ran benchmarks using both methods on batches of ten million values using both approaches, testing for memory use with GC.GetTotalMemory(true)
and getting Stopwatch
timings for instantiation, first value access, and subsequent value accesses:
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
(I used LazyThreadSafetyMode.PublicationOnly
with the Lazy<T>'s
, which looks to be the same thread safety approach taken by LazyInitializer
by default.)
As you can see, unless I've screwed up my tests somehow (never out of the question!), under these circumstances LazyInitializer
is superior in just about every quantifiable way. It has no memory or instantiation overhead, and it's faster both for creating and retrieving the value.
So, why would you want to use Lazy<T>
? Well, first, these were the test results on my x64 system, and it's possible you might get different results under other circumstances.
Lazy<T>
can also result in clearer and more concise code. return myLazy.Value;
is a lot friendlier than return LazyInitializer.EnsureInitialized(ref myValue, () => GetValue(foo));
Additionally, Lazy<T>
makes things a lot simpler if you're dealing with a value type, or with a reference type that could legitimately be null
. With LazyInitializer
, you have to use a second boolean field to keep track of whether the value has been initialized, compounding the code clarity issue. Lazy<T>
is also simpler to use if you want stricter thread safety.
And in the grand scheme of things, most of the overhead is probably negligible for a lot of applications (although not always -- the reason I started looking into this is because I was working on an application involving millions of very small lazily-loaded values, and the 32-byte-per-instance overhead of Lazy<T>
was actually starting to become inconvenient).
In the end, unless your application is very memory-intensive, I think it's usually going to be a matter of personal preference. For non-null reference types, I personally think LazyInitializer.EnsureInitialized<T>()
is a more elegant approach, but I can dig the code clarity argument too.
Lazy<T>
(MSDN) is a generic wrapper which allows creating an instance of T
on demand by holding a T
factory method (Func<T>
) and calling it when Value
property getter is accessed.
LazyInitializer
- static class with a set of static methods, this is just a helper which uses Activator.CreateInstance() (reflection) able to instantiate a given type instance. It does not keep any local private fields and does not expose any properties, so no memory usage overheads.
Worth noting that both classes uses Func<T>
as instance factory.
MSDN says in few words about LazyInitializer
class:
These routines avoid needing to allocate a dedicated, lazy-initialization instance, instead using references to ensure targets have been initialized as they are accessed.
PS: I found interesting a way how LazyIntiializer
checks whether instance already initialized, it just compare a passed in reference to a default(T)
, nice:
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; }
What seems strange to me, it creates a new instance each time before an actual check:
T t = valueFactory(); // ... and only then does check
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With