Click here to Skip to main content
Click here to Skip to main content

Tagged as

Go to top

Lazy Alternatives - LazyAndWeak and BackgroundLoader

, 1 Dec 2011
Rate this:
Please Sign up or sign in to vote.
This article will present two alternatives to Lazy.

Introduction

This article will present two alternatives to Lazy. One of them is focused on low memory use and the other focused on responsiveness.

Background

.NET 4 added the Lazy class. Its purpose is to allow fast load times and reduce memory consumption.

But, should I say that I consider Lazy class... too lazy? There are two problems that I see when using the Lazy class:

  1. The application loads fast, but then you must wait for each item that you access for the first time.
  2. If you load an item to use it only once, it will be kept in memory forever (ok... until the lazy object itself is collected).

So, to solve those problems, I decided to create my own solution, which I will present here.

Lazy Alternatives

I really wanted to create a solution that is both responsive and that avoids using memory when it is not needed. But unfortunately that's impossible... at least for me and as a generic purpose solution. But I can solve one of those problems at a time.

So I did it, as two different classes:

  • LazyAndWeak - Better memory management
  • BackgroundLoader - Better responsiveness

LazyAndWeak

For human beings, being lazy is usually bad. Being weak too is even worse. But for programming languages, being lazy and weak is good, especially when we want to save memory.

LazyAndWeak only creates its Value when it is first requested, as happens with Lazy class. But it also stores the value as a weak-reference, so it can be collected if memory is needed. Ok, it is a bit more than that. To avoid values to be collected at each garbage collection, I use my GCUtils.KeepAlive method so recently used items are not collected in the next full collection, so constantly used items will always be in memory, even after a full collection.

The big downside here is that after the item is unloaded from memory, if it is needed again, the user will need to wait again and any value that was stored in such item will be lost. So, it is very important that the constructor/creator knows how to get the most up-to-date information.

BackgroundLoader

The BackgroundLoader class goes in the opposite direction of LazyAndWeak. Instead of creating items only when requested and then allowing them to die, it tries to load all items in the background, trying not to affect performance of the application and then keeps them there. So, you load the application in a very fast manner, similar to what happens to any Lazy alternative but then when a CPU is idle, it starts loading the items that you didn't use yet.

I say that it goes in the opposite direction because it will not save any memory, as sooner or later all the items will be loaded and kept in memory. But except from the very first item (in case the user requests it as soon the application is loaded), the user will not need to wait for items to load. It opens the application (in a very fast manner), maybe wait for the very first operation to load its items but, later, any other operation will be done instantly as the items will be already loaded.

When To Use Each One?

In my opinion, never use Lazy. Maybe I am too drastic, but I don't see a real situation were Lazy only will be better. For example, if your application has 1000 menu items, each one with a slow load-time, and your users are probably only using 10 of those 1000 menu items, then it is OK.

But what happens when the user does load those 1000 items? They will be kept in memory forever. So, the user will need to wait 1000 times and then those will be there forever (so new requests will not wait).

But if those 1000 items consume too much memory, I'll say that you should use LazyAndWeak, after all the computer gets slower when running out-of-memory. If you think it is OK to keep all of them in memory, then use BackgroundLoader as the user will wait for the program to load, maybe will wait for the first menu item to load... and if he keeps enough time there, when he uses any other item it will be already in memory, without the need to wait again.

In fact, for very large projects, I usually open the application, go out for a while and then return, expecting everything to be loaded. I consider it frustrating that, in Visual Studio, I end-up waiting again when I try to load an ASP.NET project for the first time or a WPF one.

Implementation

I know CodeProject is for code... but should I really show the code here? I think explaining the basic idea is enough. So, I will only explain the idea.

LazyAndWeak uses a lock when creating the value (so two threads will not create duplicate values). When accessing the Value, a call to GCUtils.KeepAlive is made. I explained that class in one of my first articles, WeakReferences as a Good Caching Mechanism. The main problem of using WeakReferences only is that items are discarded at every collection, even if they were recently used. This class forbids them to be collected at the next collection but allows them to be collected if a second collection happens and they are still unused.

BackgroundLoader is harder. A "loader" thread is created. Each time a LazyLoader is created, it registers itself inside that thread and sets an event (ManagedAutoResetEvent) so the loader thread starts to run. If 1000 items are registered, they will be loaded in order (there is not the risk of 1000 threads trying to load their items). This class also uses locking when accessing its Value so if it is not loaded yet, it loads it immediately and removes this BackgroundLoader instance from the loader class, as it will be already loaded.

Also, there is the problem that you may create the background loader and then you discard it (in the sample project, when you change from one directory to another). That's why I implemented the IDisposable interface. If the item is not loaded yet, it is in the list of "to load" items. If you discard it, it simply removes such item from the "to load" list.

How to Use the Classes

Using those classes is very similar to using the .NET Lazy class. You simply create the LazyAndWeak<SomeType> or BackgroundLoader<SomeType> at the very first moment, probably with a declaration like this:

private readonly LazyAndWeak<SomeType> field = new LazyAndWeak<SomeType>();

And when you need to access the SomeType instance, you must access the Value property of the created field.

It is important that SomeType has a default constructor or that you give a creator delegate to it, or you will get an exception. Also, as happens with lazy, those helper objects are only useful to hold slow loading or memory-hungry objects. Don't use them for fast and small objects, as the helper objects themselves consume memory.

Sample

The attached sample is a very simple image visualizer. Its purpose is only to show the differences of the various techniques.

When you enter any directory, all image names are read and some type of lazy-loading will be done. When just opening or scrolling large folders, you will see red lines instead of images. Red lines means such images are not still in memory.

If you force collection, already loaded images will be reloaded using LazyAndWeak (which shows it worked) but will not have any effects on BackgroundLoader or custom Lazy.

I forced a 100 milliseconds delay when loading images. That was on purpose to make the differences more visible as loading images is not that slow.

If you are using BackgroundLoader, when you change directory, it will stop loading the old files. That's why Dispose was needed. If I didn't do that, if I entered directory A, then B... B will only load after loading all (useless) A files.

History

  • 1st December, 2011: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Paulo Zemek
Architect
Canada Canada
I started to program computers when I was 11 years old, as a hobbist, programming in AMOS Basic and Blitz Basic for Amiga.
At 12 I had my first try with assembler, but it was too difficult at the time. Then, in the same year, I learned C and, after learning C, I was finally able to learn assembler (for Motorola 680x0).
Not sure, but probably between 12 and 13, I started to learn C++. I always programmed "in an object oriented way", but using function pointers instead of virtual methods.
 
At 15 I started to learn Pascal at school and to use Delphi. At 16 I started my first internship (using Delphi). At 18 I started to work professionally using C++ and since then I've developed my programming skills as a professional developer in C++ and C#, generally creating libraries that help other developers do they work easier, faster and with less errors.
 
Want more info or simply want to contact me?
Take a look at: http://paulozemek.azurewebsites.net/
Or e-mail me at: paulozemek@outlook.com
 
Codeproject MVP 2012
Microsoft MVP 2013

Comments and Discussions

 
QuestionReactive Extension (Rx)? Pinmemberunknowndentified101111-Dec-11 20:36 
AnswerRe: Reactive Extension (Rx)? PinmemberPaulo Zemek2-Dec-11 0:16 
SuggestionLazyAndWeakAndReactiveAndDependent (LWRD) PinprotectorAspDotNetDev1-Dec-11 9:02 
GeneralRe: LazyAndWeakAndReactiveAndDependent (LWRD) PinmemberPaulo Zemek1-Dec-11 9:41 
GeneralRe: LazyAndWeakAndReactiveAndDependent (LWRD) PinprotectorAspDotNetDev1-Dec-11 10:22 
GeneralRe: LazyAndWeakAndReactiveAndDependent (LWRD) PinmemberPaulo Zemek1-Dec-11 10:49 
Now I understood a little more about your idea... and still feel a little lost.
OK. I agree that checking for null is against the Lazy class itself.
But by the way my BackgroundLoader works, if you have A and B, it will first load A and then load B, even if they are unrelated.
 
If B depends on A, then my two solutions are the "best" I can see as a generic purpose solution.
Or A instantiates B, so you can create the B property directly, but it will redirect to a.Value.b.Value, or B will have a creator delegate that will use A.
 
---
 
Finally... if I understood your idea... but I am not sure:
About the printing functionality... maybe all this is related to a lazy of lazy.
 
Your program loads. While you don't use a printable grid or a printable image, there is no need to load the printing functionality, which both use.
As soon as you load a grid or an image, the printing functionality is "scheduled" to load (this is the responsability of BackgroundLoader class).
 
But, in the scenario you are telling me, you don't want to load the Printing functionality before you have any printable object.
 
Well... my initial work-around (so, it is not the ultimate solution) is:
Create a PrintingFunctionality class.
Such class has a Get() method, that returns the Lazy (Background loader) instance.
It is a method, not a property, because the callers may simple call it to instantiate the static class, without using it.
Then, the Printable objects call it when they are created... and use it later.
 
But... considering that such PrintingFunctionality is becoming available all the time after their loading... I will not make it that way... I will simple use the BackgroundLoader.
In fact, all "static" functionalities that today are lazy loaded but after are kept in memory will be BackgroundLoader to me. I will even like to be able to use BackgroundLoader over the static classes, as they use the custom Lazy pattern internally.
Do you want to create a new programming language?
Do you want to know how to create a virtual machine?
Are at least interested on how they work?
So, see my article: POLAR

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140905.1 | Last Updated 1 Dec 2011
Article Copyright 2011 by Paulo Zemek
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid