.NET

Complete Guide to Lazy Loading – Lazy

In creating performance-centric applications one has to be very cautious about how and when objects are created and destroyed. An early creation of an object is equally dangerous as is delayed clean-up. When an object is created before it is actually required, the object finds itself residing in a memory stack at much distant location from the place it is referenced – hence requiring more POP and PUSH statements to retrieve its value each time it is referenced.

To optimize this, C# 4.0 introduced Lazy object loading. Lazy loading refers to creating and initializing of objects only when it is required for the first time. That means, you can define the object whenever you wish to, but it actually gets created only when you access its method/property/function. So this essay talks about Lazy loading in C# 4.0

Until C# 3.0, you could implement lazy loading explicitly but with C# 4.0 you can just use Lazy class to implement lazy loading. It is faster, and standard approach to loading objects and is much recommended for better performance and memory optimization.

Using Lazy<T>

For this essay, we will create a Console application and experiment on a very small & simple class Database (as I don’t like using Foo for examples). The class just has one property Name.

class Program
    {
        static void Main(string[] args)
        {
            // Defining database
            Lazy<Database> database = new Lazy<Database>();
            Console.WriteLine(“Defined database object. Is database object created?”);
            // Check if database object has been initialized
            if (database.IsValueCreated)
                Console.WriteLine(“Database is initialized now!”);
            else
                Console.WriteLine(“Database is not initialized yet!”);
            // Will throw an exception.. as it does not have parameter-less constructor
            Console.WriteLine(“Database: Name =” + database.Value.Name);
            // Check if database object has been initialized
            if (database.IsValueCreated)
                Console.WriteLine(“Database is initialized now!”);
            Console.ReadKey();
        }
    }
    public class Database
    {
        public string Name { get; set; }
        public Database(string name)
        {
            Console.WriteLine(“Database object constructor called”);
            Name = name;
        }
    }

When you execute this program it gives you the result as:

Defined database object. Is database object created?
Database is not initialized yet!

followed by an exception: The lazily-initialized type does not have a public, parameterless constructor.

Okay, let’s add a parameter-less constructor to Database class and re-run it. The new Database class appears like:

public class Database 
    { 
        public string Name { get; set; } 
        public Database() 
        { 
            Console.WriteLine(“Database object constructor called”); 
            Name = “MyName”; 
        } 
    } 

The new output is:

Defined database object. Is database object created? 
Database is not initialized yet! 
Database object constructor called 
Database: Name =MyName 
Database is initialized now!

Let’s analyse this. When we defined object database (of Lazy), CLR created an object of Lazy wrapper but not the object of Database class. When we accessed the property Name of the database object (database.Value.Name), an object of Database class was created & Database constructor was called. But does it mean, lazy loading always requires a parameter-less constructor of the class that needs to be loaded lazily? Well, if that is the case it is not the best fit for Business Applications. So let’s fix that.

// For parameter-based constructor 
            Lazy<Database> database = new Lazy<Database>(() => 
                { 
                    Database internalObject = new Database(“MyNewName”); 
                    return internalObject; 
                }); 

The new output is:

Defined database object. Is database object created? 

Database is not initialized yet!
Database object constructor called Database: Name =MyNewName 

Database is initialized now!

Thread-safety with Lazy<T>

If you are building performance centric applications, you would definitely want to use the power of multiple processors/cores using threads. So is Lazy class thread-safe? Well yes, it’s thread-safe. You have got multiple options for thread-safety with lazy loading

Lazy<Database> database = new Lazy<Database>(() => 
            { 
                Database internalObject = new Database(“MyNewName”); 
                return internalObject; 
            }, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication

ExecutionAndPublication

Only single thread is responsible for initializing of the object (Lazy) in a thread-safe manner. When you are using this mode, it is preferable not to use lock in the constructor of the object used with Lazy (here Database class). This mode can cause a lot of trouble on heavy use because the possibility of deadlocks rises with each dependency between the objects.

static void Main(string[] args) 
        { 
            Lazy<database> database = new Lazy<database>(() => 
            { 
                Database internalObject = new Database(“MyNewName”); 
                return internalObject; 
            }, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication); 
            ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessDatabase), database); 
            ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessDatabase), database); 
            Console.ReadKey(); 
        } 
        static void ProcessDatabase(object input) 
        { 
            Lazy<database> database = input as Lazy<database>; 
            Thread.Sleep(10); 
            database.Value.Counter++; 
            Console.WriteLine(“Counter : “ + database.Value.Counter + ” at “ + DateTime.Now.ToString()); 
        } 

The output of following code is:

Database object constructor called 

Counter : 1 at 23/10/2011 20:59:33 

Counter : 2 at 23/10/2011 20:59:33

PublicationOnly

All threads create an instance of the object, but only the first completely initialized one is published to all threads. This reduces the amount of deadlocks that can be caused with ExecutionAndPublication. However, in case multiple-threads can create an object and persist different values.

Lazy<database> database = new Lazy<database>(() => 
            { 
                Database internalObject = new Database(“MyNewName”); 
                return internalObject; 
            }, System.Threading.LazyThreadSafetyMode.PublicationOnly); 

The output of the following code is:

Database object constructor called 

Database object constructor called 
Counter : 1 at 23/10/2011 20:56:19 

Counter : 2 at 23/10/2011 20:56:19

None

This is by-far the most risky mode as it is not thread-safe if the instance is accessed from multiple threads. The behavior is undefined and should be used only if high-performance is desirable on single-thread applications

Exception Handling with Lazy<T>

Lazy<T> handles exceptions in two ways 

  • For a single-threaded lazy-loading, the exception is thrown directly to the consuming class 
  • For multiple-threaded lazy-loading (using ExecutionAndPublication mode), the exception during initializing the object is cached and thrown at the first access of the object. So when the object is initialized, there won’t be any exception thrown. 

For multi-threaded applications, it is preferable to handle exceptions at each thread level rather than aggregating them at the main-thread.  
 
Final words

Lazy loading using Lazy can be used in many scenario’s such as: 

  • Data layer – with ADO.NET, or Entity Framework 
  • Reflection – loading assemblies, types, MEF  
  • Caching of objects, domain entities 

But one should take care of many design related issues while using lazy loading 

  • Inconsistent state of objects 
  • Hiding of business requirements due to abstraction 

I hope this essay helps you to understand and implement lazy loading with C# 4.0

Reference: Complete Guide to Lazy Loading – Lazy from our NCG partner Punit Ganshani at the Punit Ganshani’s blog.

Related Articles

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button