NET中具有ObjectCache的对象的过期时间 [英] Cache object with ObjectCache in .Net with expiry time

查看:96
本文介绍了NET中具有ObjectCache的对象的过期时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我被困在一个场景中. 我的代码如下:

I am stuck in a scenario. My code is like below :

更新:它与如何使用数据缓存无关,我已经在使用它及其工作了,与扩展它有关,因此该方法不会在到期时间和从外部来源获取新数据之间进行调用

object = (string)this.GetDataFromCache(cache, cacheKey);

if(String.IsNullOrEmpty(object))
{
  // get the data. It takes 100ms
  SetDataIntoCache(cache, cacheKey, object, DateTime.Now.AddMilliseconds(500));
}

因此,用户访问缓存并从中获取数据(如果该项目过期),它调用并从服务获取数据并保存,以防万一,问题是,当有待处理的请求时(请求正在进行中)该服务发送另一个请求,因为该对象已过期.最终,每秒最多应该有2-3个呼叫,并且每秒有10-20个呼叫到外部服务.

So user hit the cache and get data from it if the item expire it calls and get the data from service and save it in case , the problem is , when ever there is a pending request ( request ongoing ) the service send another request because the object is expired . in final there should be max 2-3 calls/ seconds and there are 10-20 calls per seconds to external service .

是否有任何最佳方法,因此在请求时间与使用数组和时间戳等创建自己的自定义类之间没有冲突?

Is there any optimal way to doing it so no conflict between requests time other then creating own custom class with arrays and time stamps etc?

顺便说一下,缓存的保存代码是-

btw the saving code for cache is-

private void SetDataIntoCache(ObjectCache cacheStore, string cacheKey, object target, DateTime slidingExpirationDuration)
{
  CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();

  cacheItemPolicy.AbsoluteExpiration = slidingExpirationDuration;
  cacheStore.Add(cacheKey, target, cacheItemPolicy);
}

推荐答案

我从System.Runtime.Caching.ObjectCache一起使用" rel =" nofollow> MvcSiteMapProvider .完整的实现具有一个ICacheProvider接口,该接口允许在System.Runtime.CachingSystem.Web.Caching之间进行交换,但这是应满足您需求的精简版本.

I have adapted the solution from Micro Caching in .NET for use with the System.Runtime.Caching.ObjectCache for MvcSiteMapProvider. The full implementation has an ICacheProvider interface that allows swapping between System.Runtime.Caching and System.Web.Caching, but this is a cut down version that should meet your needs.

此模式最引人注目的功能是,它使用轻量级版本的惰性锁来确保缓存过期后仅1次从数据源加载数据,而不管尝试加载的并发线程数是多少.数据.

The most compelling feature of this pattern is that it uses a lightweight version of a lazy lock to ensure that the data is loaded from the data source only 1 time after the cache expires regardless of how many concurrent threads there are attempting to load the data.

using System;
using System.Runtime.Caching;
using System.Threading;

public interface IMicroCache<T>
{
    bool Contains(string key);
    T GetOrAdd(string key, Func<T> loadFunction, Func<CacheItemPolicy> getCacheItemPolicyFunction);
    void Remove(string key);
}

public class MicroCache<T> : IMicroCache<T>
{
    public MicroCache(ObjectCache objectCache)
    {
        if (objectCache == null)
            throw new ArgumentNullException("objectCache");

        this.cache = objectCache;
    }
    private readonly ObjectCache cache;
    private ReaderWriterLockSlim synclock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);

    public bool Contains(string key)
    {
        synclock.EnterReadLock();
        try
        {
            return this.cache.Contains(key);
        }
        finally
        {
            synclock.ExitReadLock();
        }
    }

    public T GetOrAdd(string key, Func<T> loadFunction, Func<CacheItemPolicy> getCacheItemPolicyFunction)
    {
        LazyLock<T> lazy;
        bool success;

        synclock.EnterReadLock();
        try
        {
            success = this.TryGetValue(key, out lazy);
        }
        finally
        {
            synclock.ExitReadLock();
        }

        if (!success)
        {
            synclock.EnterWriteLock();
            try
            {
                if (!this.TryGetValue(key, out lazy))
                {
                    lazy = new LazyLock<T>();
                    var policy = getCacheItemPolicyFunction();
                    this.cache.Add(key, lazy, policy);
                }
            }
            finally
            {
                synclock.ExitWriteLock();
            }
        }

        return lazy.Get(loadFunction);
    }

    public void Remove(string key)
    {
        synclock.EnterWriteLock();
        try
        {
            this.cache.Remove(key);
        }
        finally
        {
            synclock.ExitWriteLock();
        }
    }


    private bool TryGetValue(string key, out LazyLock<T> value)
    {
        value = (LazyLock<T>)this.cache.Get(key);
        if (value != null)
        {
            return true;
        }
        return false;
    }

    private sealed class LazyLock<T>
    {
        private volatile bool got;
        private T value;

        public T Get(Func<T> activator)
        {
            if (!got)
            {
                if (activator == null)
                {
                    return default(T);
                }

                lock (this)
                {
                    if (!got)
                    {
                        value = activator();

                        got = true;
                    }
                }
            }

            return value;
        }
    }
}

用法

// Load the cache as a static singleton so all of the threads
// use the same instance.
private static IMicroCache<string> stringCache = 
    new MicroCache<string>(System.Runtime.Caching.MemoryCache.Default);

public string GetData(string key)
{
    return stringCache.GetOrAdd(
        key,
        () => LoadData(key),
        () => LoadCacheItemPolicy(key));
}

private string LoadData(string key)
{
    // Load data from persistent source here

    return "some loaded string";
}

private CacheItemPolicy LoadCacheItemPolicy(string key)
{
    var policy = new CacheItemPolicy();

    // This ensures the cache will survive application
    // pool restarts in ASP.NET/MVC
    policy.Priority = CacheItemPriority.NotRemovable;

    policy.AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(1);

    // Load Dependencies
    // policy.ChangeMonitors.Add(new HostFileChangeMonitor(new string[] { fileName }));

    return policy;
}

注意::如前所述,您可能无法通过缓存一个耗时100ms的值而仅获取500ms来获得任何收益.您应该选择更长的时间来将项目保存在缓存中.这些项目真的在数据源中具有很大的可变性,可以快速更改吗?如果是这样,也许您应该考虑使用ChangeMonitor来使任何过时的数据无效,这样您就不会花费太多的CPU时间来加载缓存.然后,您可以将缓存时间更改为分钟而不是毫秒.

NOTE: As was previously mentioned, you are probably not gaining anything by caching a value that takes 100ms to retrieve for only 500ms. You should most likely choose a longer time period to hold items in the cache. Are the items really that volatile in the data source that they could change that quickly? If so, maybe you should look at using a ChangeMonitor to invalidate any stale data so you don't spend so much of the CPU time loading the cache. Then you can change the cache time to minutes instead of milliseconds.

这篇关于NET中具有ObjectCache的对象的过期时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆