tags:

views:

91

answers:

4

I currently cache the result of a method invocation.

The caching code follows the standard pattern: it uses the item in the cache if it exists, otherwise it calculates the result, caching it for future calls before returning it.

I would like to shield client code from cache misses (e.g. when the item has expired).

I am thinking of spawning a thread to wait for the lifetime of the cached object, to then run a supplied function to repopulate the cache when (or just before) the existing item expires.

Can anyone share any experience related to this? Does this sound like a sensible approach?

I'm using .NET 4.0.

+1  A: 

Since this is ASP.NET, the Cache.Insert() method allows you to specify a callback delegate.

Does this sound like a sensible approach?

Yes, the callback (and File-dependency) are supplied for exactly this kind of situation. You still have ro make a trade of between resources, latency and out-of-dateness.

Henk Holterman
This answers my original question as I envisaged. I am unsure of the usefulness of the distinction Steven Sudit makes between caching and snapshotting (I haven't come across the distinction before). I'd be interested to learn more.
Ben Aston
+2  A: 

Here's a cache that never expires anything:

var cache = new ConcurrentDictionary<TKey, TValue>();

var value = cache.GetOrAdd(someKey, key => MyMethod(key));

Does that help?


Here's a cache that never expires anything and refreshes the value after a certain lifetime:

var cache = new ConcurrentDictionary<TKey, Tuple<TValue, DateTime>>();

var value = cache.AddOrUpdate(someKey,
             key => Tuple.Create(MyMethod(key), DateTime.Now),
    (key, value) => (value.Item2 + lifetime < DateTime.Now)
                  ? Tuple.Create(MyMethod(key), DateTime.Now)
                  : value)
                  .Item1;

Does that help?

dtb
But it never refreshes anything either
Henk Holterman
OK, nice addition. But the ASP cache also has a priority mechanism abs timeout, sliding timeout, defaults, ... (still +1 :)
Henk Holterman
I would generally prefer to let a value expire when it's old, then postpone getting a new value until and unless it's actually desired.
Steven Sudit
@Steven: that makes way too much assumptions about the OP's situation.
Henk Holterman
@Henk: Perhaps, but what you're describing isn't caching, it's snapshotting. For example, if I have a table of rarely-changing data, such as the list of states in the USA, I don't want to hit the database each time, but I also don't want to cache the list forever because, hey, things change. So I generate a snapshot that expires after some reasonable but arbitrary period of time (an hour, a day) and then replace it with a new snapshot. That's not caching. Caching would be keeping values that expire only to make room for more useful ones, with misses resolved on an as-needed basis.
Steven Sudit
@Steven, we're descending into semantics. A cache with auto reload looks a lot like a Snapshot but I could still point out differences. A more practical point: ASP.NET does have a Cache object but not a Snapshot object. But let's cut this comment-trail, you could ask this as a Question.
Henk Holterman
@Henk: I'm not interesting is semantics, but rather in pointing out a genuine distinction. By definition, a cache is something that can be sized down to zero but still work for read-through and write-through. You're talking about a different animal entirely, which uses cache-like algorithms but towards a different end. As for a question, I'm not sure what I'd ask.
Steven Sudit
A: 

There doesn't seem to be any point in expiring an object just to immediately recreate it. Just turn off expiration; dtb shows how.

Steven Sudit
And the refresh? That's another function of a cache.
Henk Holterman
How is the old object any worse than the new one? If it's not, then let's leave it alone. On the other hand, if the OP had a simple wrapper that amounted to "get it from the cache if possible, else create it and incidentally add it to the cache", this would be fine.
Steven Sudit
If it is a static calculation you would be right. But consider a query or webservice. Caching is usually a trade-of between performance and freshness. And the OP addressed the other part: preventing cache-misses
Henk Holterman
You can't prevent cache misses. That's why it's called a cache.
Steven Sudit
@Henk: Sorry, forgot the prefix again.
Steven Sudit
Steven, if you reload after expiration (and maybe even preload on startup) you _can_ prevent cache misses. No problem.
Henk Holterman
@Henk: If a cache miss is impossible, it's not a cache.
Steven Sudit
+2  A: 

A new addition to the .NET Framework 4.0 is the MemoryCache Class

Quote from the Docs:

The MemoryCache class is similar to the ASP.NET Cache class. The MemoryCache class has many properties and methods for accessing the cache that will be familiar to you if you have used the ASP.NET Cache class

You could use the AddOrGetExisting Method to get or create a CacheItem if does not exist.

Islam Ibrahim
Nice link, didn't know about that. But AddOrGetExisting would still count as a cache-miss, Ben should use a callback. That seems supported.
Henk Holterman