使用IMemoryCache每个存储区单例吗?

时间:2019-07-03 16:26:04

标签: c# caching .net-core

我正在将IMemoryCache集成到项目中,并且竭尽全力确保每个存储库或提供程序中的密钥不冲突(即提供密钥空间)。但是后来我想到了,为什么不只为每个存储库/提供者提供他们自己的IMemoryCache单例实例-即一个命名的单例。这将确保密钥永远不会冲突,并且一个存储库永远都无法访问另一个存储库的内部状态。我的原始方面还说,这可能会提高性能,因为现在每个存储库都没有竞争IMemoryCache的内部锁。

但是我不会假装理解IMemoryCache如何管理所有逻辑。也许拥有一个应用程序范围内的单例实例很重要,这样它才能以更高性能的方式管理缓存条目的生存期。

基本上,我从未见过有人使用IMemoryCache的单一存储库模式,因此我正在征求有关此方法的反馈。

谢谢

2 个答案:

答案 0 :(得分:2)

我相信原始的.NET完整框架MemoryCache打算通过MemoryCache.Default属性用作单例实例。这是因为它对称为MemoryPressure的东西起作用。关于这个神奇的MemoryPressure实际计算方式的文献几乎为零。毫无疑问,它在多个实例上可能并不太聪明。

现在看来,首选是在缓存上设置大小限制。在dotnet核心版本中,MemoryCache.Default静态属性不再存在,并且似乎没有警告表明多实例是反模式。此外,似乎MemoryCacheOptions.CompactOnMemoryPressure现在已过时,首选提供固定的大小。我看不到使用多个实例的任何问题。

答案 1 :(得分:0)

这是我创建的linqpad示例。我认为这就是您要寻找的东西:

void Main()
{
    DataTable dt = new DataTable();

    DateTime start = DateTime.Now;

    Random _rand = new Random();
    List<int> result = Enumerable.Range(1, 6000)
    .Select(x => x++)
    .ToList();
    result.AsParallel<int>().ForAll(c =>
    {
        Util.GetFromCache("datatable", c);
        System.Threading.Thread.Sleep(1);
    });

    DateTime.Now.Subtract(start).Seconds.Dump();
    "....DONE.....".Dump();

}

public static class Util
{
    private static readonly object _Lock = new object();

    public static object GetFromCache(string cachename, int i)
    {
        object obj = MemoryCacher.GetValue(cachename);
//      if (i == 5) //when time is up - reset token, update DB and add to cache es example i set a count=5
//      {
//          obj = null;
//          MemoryCacher.Delete(cachename);
//      }
        if (obj == null)
        {
            lock (_Lock)
            {
                obj = MemoryCacher.GetValue(cachename);
                if (obj == null)
                {
                    $"{i} from DATA".Dump();
                    obj = GetData();
                    MemoryCacher.Delete(cachename);
                    MemoryCacher.Add(cachename, obj, DateTimeOffset.Now.AddSeconds(5));
                    return obj;
                }
                $"{i} from CACHE with lock".Dump();
            }
        }
        $"{i} from CACHE".Dump();
        return obj;
    }

    public static DataTable GetData()
    {
        DataTable dt = new DataTable();

        FileInfo fi = new FileInfo("c:\\1\\text.txt");
        dt = CSVtoDS(fi.FullName, true).AsEnumerable().Take(10).CopyToDataTable();
        return dt.Dump("call");
    }

    public static DataTable CSVtoDS(string filePath, bool isFirstLineHeader)
    {
        DataTable dt = new DataTable();
        using (TextReader tr = File.OpenText(filePath))
        {
            string strRow = string.Empty;
            string[] arrColumns = null;
            int indx = 0;
            while ((strRow = tr.ReadLine()) != null)
            {
                //set up columns
                if (indx == 0)
                {
                    arrColumns = strRow.Split('\t')[0].Split(',').Select(x => x.Replace(" ", "_")).ToArray();
                    if (dt.Columns.Count != arrColumns.Length + 1)
                        for (int i = 0; i <= arrColumns.Length - 1; i++)
                        {
                            if (isFirstLineHeader)
                                dt.Columns.Add(new DataColumn(arrColumns[i]));
                            else
                                dt.Columns.Add(new DataColumn());
                        }
                    indx = 1;
                }
                else
                {
                    DataRow dr = dt.NewRow();
                    dr.ItemArray = strRow.Split(',');
                    dt.Rows.Add(dr);
                }
            }
            tr.Close();
        }
        return dt;
    }

    public static class MemoryCacher
    {
        public static object GetValue(string key)
        {
            MemoryCache memoryCache = MemoryCache.Default;
            return memoryCache.Get(key);
        }

        public static void Add(string key, object value, DateTimeOffset absExpiration)
        {
            MemoryCache memoryCache = MemoryCache.Default;
            memoryCache.Set(key, value, absExpiration);
        }

        public static void Delete(string key)
        {
            MemoryCache memoryCache = MemoryCache.Default;
            if (memoryCache.Contains(key))
            {
                memoryCache.Remove(key);
            }
        }
    }
}