系统.runtime.caching的性能表现

28
我比较了.NET 4.0中的system.runtime.caching和Enterprise Library Caching Block的性能,令我惊讶的是,在从缓存项获取大量数据集时,前者表现非常糟糕。
Enterprise Library在约0.15ms内获取100个对象,在约0.25ms内获取10000个对象。这很快,对于进程内缓存而言是自然的,因为实际上不需要复制任何数据(只需使用引用即可)。
.NET 4.0的缓存在约25ms内获取100个对象,在约1500ms内获取10000个对象!与Enterprise Library相比,这非常慢,这让我怀疑缓存是在进程外进行的。
我是否遗漏了某些配置选项,例如启用进程内缓存,还是Enterprise Library Caching Block确实快了这么多?
更新:
以下是我的基准测试:
首先,我从数据库加载数据到缓存中(与基准测试分开)。
我使用计时器来测量毫秒级别的get方法时间:
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缓存

    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());
    }

为确保测试的可靠性,执行1000次基准测试来计算获取对象的平均时间。计时器是我使用的自定义计时器,任何计算毫秒的计时器应该都可以使用。

有趣的是,“myObject”具有众多引用。如果涉及任何序列化(例如在分布式缓存中),我会理解为什么此对象的性能不同,但这两个都是进程内缓存,理论上应该没有太大的差异。


你正在使用MemoryCache还是测试了自己的实现?根据MSDN,MemoryCache是inproc。 - ata
我现在已经添加了基准测试代码。 - robertherber
7
你应该使用Stopwatch类。 - SLaks
1
我认为你的测试肯定有问题。使用MSDN的高性能时间(它查询性能计数器),从.NET 4内存缓存中检索10K个枚举平均需要0.007毫秒,而10K次检索需要7.44毫秒。 - Keith
3
“在大约0.15毫秒内处理100个对象,在约0.25毫秒内处理10000个对象”-值得注意的是,循环调用相同的代码应该大致呈线性比例增长,但实际情况并非如此。100倍的调用只需要比原来多66%的时间。此外,在循环内部不应创建新计时器对象或编写响应内容。” - Bengie
显示剩余4条评论
1个回答

9
我的猜测是您的缓存内容或策略的细节不同。没有看到设置或插入,很难确切地说。

无论如何,这两个库具有不同的性能特点,哪个更好显然取决于情况。

可能我的测试(以下代码)过于简单,不能代表性,但在我的机器上运行,MemoryCache大约快了10倍。

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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接