Подтвердить что ты не робот

Производительность system.runtime.caching

Я сравнил производительность system.runtime.caching в .NET 4.0 и блоке кэширования корпоративной библиотеки, и, к моему удивлению, он очень страшно сравнивается при извлечении больших коллекций данных из элементов кэша.

Корпоративная библиотека извлекает 100 объектов примерно в 0,15 мс, 10000 объектов примерно в 0,25 мс. Это быстро и естественно для кэша в процессе, потому что не нужно копировать данные (только ссылки).

Кэширование .NET 4.0 извлекает 100 объектов примерно за 25 мс, 10000 объектов примерно за 1500 мс! Это ужасно медленно в сравнении, и это заставляет меня подозревать, что кеширование выполнено вне процесса.

Мне не хватает какой-либо опции конфигурации, например, чтобы включить кэширование в процессе, или это блок кэширования корпоративной библиотеки действительно намного быстрее?

Обновление

Здесь мой бенчмарк:

Сначала я загружаю данные из базы данных в кеш (отдельно от эталона).

Я использую таймер вокруг методов get для измерения времени в миллисекундах:

Кэширование EnterpriseLibrary

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" есть множество ссылок. Если бы была какая-либо сериализация, я бы понял, почему производительность отличается для этого объекта (например, в распределенном кэшировании), но это как временные кэши, которые теоретически должны работать без каких-либо существенных различий.

4b9b3361

Ответ 1

Я предполагаю, что детали вашего содержимого кэша или политики не совпадают. Не видя установки или вставки, трудно точно сказать, как это сделать.

Независимо от того, что две библиотеки имеют разные характеристики производительности, и какая из них лучше четко зависит от ситуации.

Вероятно, мой тест (код ниже) слишком прост, чтобы быть репрезентативным, но с его запуском на моей машине 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>