Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,124 | Comments: 45,470

filter by tags archive

The contracts of Lazy<T> vs Task<T>

time to read 3 min | 409 words

There was a question about our use of Task<T> and Lazy<T> in RavenDB, and I thought that this is a subtle thing that deserve more than a short email.

The basic difference between Lazy<T> and Task<T> are the kind of contracts that they express.

  • Lazy<T> represent a potentially expensive operation that has been deferred. The promise given is that the lazy’s value will be generated the first time that it is needed.
  • Task<T> represent a potentially expensive operation that is currently executing. The promise is that the task’s value will be available on request, hopefully already there by the time you asked.

The major difference is when we are actually starting the operation. Most often, when we return a task, we return a reference to an scheduled / executing task, which will complete whatever or not the task’s result will be accessed. Conversely, a lazy’s whose value was never accessed is not something that will ever execute.

The use cases for them tend to be quite different.

Lazy<T> is used a lot of the time as a way to handle once and only once creation (basically, a safe singleton pattern), and for actually deferring the execution of work. Sometimes you can avoid having to do something, and it is easier to give a caller a lazy object and only have to pay for that additional work if they access the data.

Task<T> is primarily used to actually parallelize the work, so you’ll have it running while you are doing other stuff. Usually this is used for I/O, since that can be natively parallelized.

With RavenDB, we use Task<T> as the return type of all our async operations, allowing of to take advantage on the async nature of I/O. And we use Lazy<T> to setup a deferred call for the server. When someone actually access one of lazy’s values, we have to provide you with the answer. At this point, we can go to the server with all  the pending lazy operations, and save a lot of effort just making remote calls to the server.

In fact, in RavenDB 3.0, we have lazy support in the async API. That means that we have methods that return Lazy<Task<T>>, which means: Give me a deferred operation, that when required, will perform in an async manner. That gives me both the ability to combine requests to the server and avoid blocking up a thread while that I/O is in progress.


Frank Quednau

we can go to the server with all the pending lazy operations

What do you mean by that? If a user accesses the value of a lazy instance, it is done on that instance (one value) - what do you know about other lazy values?


The other thing I like Lazy for is avoiding I/O operations or virtual calls in constructors without needing an Initialize method or a factory.


Can't this be done using just the Task interface? I mean, task creation doesn't imply it has to run immediately and so it can also behave in a lazy manner by making a request to the server only if someone's awaiting for completion.

Ayende Rahien

Frank, You perform multiple lazy operations, such as "give me (lazily) document users/1" and "give me (lazily) the orders for users/1" This doesn't generate a server request. When you access one of those lazy values, we initiate a single server request, that execute both requests in a single round trip.

Ayende Rahien

Rafal, No, you cannot do that. There is a very distinct different between awaiting on the result of a pending task and requesting that it be calculated.

Frank Quednau

Ayende, what I mean is when you have in code:

User u = lazyUser.Value; Orders o = lazyOrders.Value;

How can you bundle that, considering it is two distinct calls?

Ayende Rahien

Frank, It looks like this:

var lazyUser = session.Lazily.LoadUser; var lazyOrders = session.QueryOrder.Where(x=> x.User == "users/1").Lazily();

// no server was touched so far

var user = lazyUser.Value;

// server was contacted for BOTH operations, in a single round trip

var orders = lazyOrders.Value;

// the data is already there from the previous call, so we don't contact the server,


So is the lazyOrders.Value lazy then? Does not appear so. What happens if the data changes in between initialising the second lazy?

Ayende Rahien

Duke, The lazyOrders.Value is getting the already retrieved value which we got in the lazyUser.Value call.

Comment preview

Comments have been closed on this topic.


  1. RavenDB 3.5 whirl wind tour: You want all the data, you can’t handle all the data - 2 days from now
  2. The design of RavenDB 4.0: Making Lucene reliable - 3 days from now
  3. RavenDB 3.5 whirl wind tour: I’ll find who is taking my I/O bandwidth and they SHALL pay - 4 days from now
  4. The design of RavenDB 4.0: Physically segregating collections - 5 days from now
  5. RavenDB 3.5 Whirlwind tour: I need to be free to explore my data - 6 days from now

And 14 more posts are pending...

There are posts all the way to May 30, 2016


  1. RavenDB 3.5 whirl wind tour (14):
    29 Apr 2016 - A large cluster goes into a bar and order N^2 drinks
  2. The design of RavenDB 4.0 (13):
    28 Apr 2016 - The implications of the blittable format
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series



Main feed Feed Stats
Comments feed   Comments Feed Stats