Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance of system.runtime.caching

I have compared the performance of system.runtime.caching in .NET 4.0 and the Enterprise Library Caching Block and to my surprise it performs terribly in comparison when fetching large data collections from cache items.

Enterprise Library fetches 100 objects in about 0,15ms, 10000 objects in about 0,25ms. This is fast, and natural for an in-process cache because no data actually needs to be copied (only references).

The .NET 4.0 caching fetches 100 objects in about 25ms, 10000 objects in about 1500ms! This is terribly slow in comparison and it makes me suspect the caching is done out-of-process.

Am I missing some configuration option, for example to enable in-process caching, or is the Enterprise Library Caching Block really this much faster?

Update

Here's my benchmark:

First, I load the data from the database to the cache (separate from the benchmark).

I use a timer around the get methods to measure the time in milliseconds:

EnterpriseLibrary Caching

Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager _cache;

public void InitCache(){
    _cache = CacheFactory.GetCacheManager("myCacheName");
}

public void Benchmark(){
    HighPerformanceTimer timer = new HighPerformanceTimer();
    timer.Start();
    myObject o = (myObject)_cache.GetData(myCacheKey);
    timer.Stop();
    Response.Write(timer.GetAsStringInMilliseconds());
}

.NET 4.0 Caching

    System.Runtime.Caching.MemoryCache _cache;

    public void InitCache(){
        _cache = new MemoryCache("myCacheName");
    }

    public void Benchmark(){
        HighPerformanceTimer timer = new HighPerformanceTimer();
        timer.Start();
        myObject o = (myObject)_cache.Get(myCacheKey);
        timer.Stop();
        Response.Write(timer.GetAsStringInMilliseconds());
    }

The benchmark is executed 1000 times to compute average time to fetch the object to ensure reliability of the test. The timer is a custom timer I use, any timer counting milliseconds should do.

The interesting thing is that the "myObject" has numerous references. If there was any serialization involved I'd understand why the performance differs for this object (like in distributed caching), but these are both in-process caches that theoretically should work without many major differences at all.

like image 626
robertherber Avatar asked Jul 01 '10 11:07

robertherber


People also ask

How does caching improve performance?

A cache's primary purpose is to increase data retrieval performance by reducing the need to access the underlying slower storage layer. Trading off capacity for speed, a cache typically stores a subset of data transiently, in contrast to databases whose data is usually complete and durable.

What is meant by cache performance?

Cache performance depends on cache hits and cache misses, which are the factors that create constraints to system performance. Cache hits are the number of accesses to the cache that actually find that data in the cache, and cache misses are those accesses that don't find the block in the cache.

What is runtime cache?

Runtime caching refers to gradually adding responses to a cache "as you go". While runtime caching doesn't help with the reliability of the current request, it can help make future requests for the same URL more reliable.

When should I use MemoryCache?

It's for when we have used data in our application or some time after, you have to remove the cache data from our system, then we can use it. This is used for data outside of the cache, like if you saved the data in a file or database and then want to use it in our application.


1 Answers

My guess is that the details of your cache contents or policies are not the same. Without seeing the setup, or the inserts, it's hard to say exactly how.

Regardless, the two libraries have different performance characteristics, and which one is better clearly depends on the situation.

Probably my test (code below) is too simple to be representative, but with it running on my machine, MemoryCache is roughly 10x faster.

class Program {             const string myCacheKey = "foo";     static ICacheManager _elCache;             static MemoryCache _rtCache;     public static void InitCache()     {                     _elCache = CacheFactory.GetCacheManager();         _elCache.Add(myCacheKey, new object());          _rtCache = new MemoryCache("cache");         _rtCache.Add(myCacheKey, new object(), new CacheItemPolicy());     }     public static string ElBenchmark(int n)     {         Stopwatch timer = new Stopwatch();         timer.Start();         for (int i = 0; i < n; i++)         {             object o = _elCache.GetData(myCacheKey);         }         timer.Stop();         return timer.ElapsedTicks.ToString();     }     public static string RtBenchmark(int n)     {         Stopwatch timer = new Stopwatch();         timer.Start();         for (int i = 0; i < n; i++)         {             object o = _rtCache.Get(myCacheKey);         }         timer.Stop();         return timer.ElapsedTicks.ToString();     }     static void Main(string[] args)     {         while (true)         {             InitCache();             StringBuilder sb = new StringBuilder();             System.Diagnostics.Debug.Write("EL: " + ElBenchmark(10000));             System.Diagnostics.Debug.Write("\t");             System.Diagnostics.Debug.Write("RT: " + RtBenchmark(10000));             System.Diagnostics.Debug.Write("\r\n");         }     } }   <?xml version="1.0"?> <configuration>    <configSections>     <section name="cachingConfiguration"          type="Microsoft.Practices.EnterpriseLibrary.Caching.Configuration.CacheManagerSettings, Microsoft.Practices.EnterpriseLibrary.Caching, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />   </configSections>   <cachingConfiguration defaultCacheManager="MyCacheManager">     <cacheManagers>       <add name="MyCacheManager" type="Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager, Microsoft.Practices.EnterpriseLibrary.Caching, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"        expirationPollFrequencyInSeconds="60"        maximumElementsInCacheBeforeScavenging="50000"        numberToRemoveWhenScavenging="1000"        backingStoreName="NullBackingStore" />     </cacheManagers>     <backingStores>       <add type="Microsoft.Practices.EnterpriseLibrary.Caching.BackingStoreImplementations.NullBackingStore, Microsoft.Practices.EnterpriseLibrary.Caching, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"        name="NullBackingStore" />     </backingStores>   </cachingConfiguration>    <startup>     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>   </startup>   </configuration> 
like image 123
solublefish Avatar answered Sep 25 '22 03:09

solublefish