GVKun编程网logo

c# – MemoryCache在第一次到期后总是返回“null”(c# memorypool)

12

如果您想了解c#–MemoryCache在第一次到期后总是返回“null”和c#memorypool的知识,那么本篇文章将是您的不二之选。我们将深入剖析c#–MemoryCache在第一次到期后总是返

如果您想了解c# – MemoryCache在第一次到期后总是返回“null”c# memorypool的知识,那么本篇文章将是您的不二之选。我们将深入剖析c# – MemoryCache在第一次到期后总是返回“null”的各个方面,并为您解答c# memorypool的疑在这篇文章中,我们将为您介绍c# – MemoryCache在第一次到期后总是返回“null”的相关知识,同时也会详细的解释c# memorypool的运用方法,并给出实际的案例分析,希望能帮助到您!

本文目录一览:

c# – MemoryCache在第一次到期后总是返回“null”(c# memorypool)

c# – MemoryCache在第一次到期后总是返回“null”(c# memorypool)

我有以下问题,我有这种缓存管理:

public class CacheManager : ICacheManager {

    private readonly ObjectCache cache;

    public CacheManager() {
        this.cache = MemoryCache.Default;
    }

    public void AddItem(string key,object itemToCache,double duration) {
        var end = DateTime.Now.AddSeconds(duration);
        this.cache.Add(key,itemToCache,end);
    }

    public T Get<T>(string key) where T : class {
        try {
            return (T)this.cache[key];
        }
        catch (Exception ex) {
            return null;
        }
    }

    public void Remove(string key) {
        this.cache.Remove(key);
    }
}

很简单

编辑I(问题文本中的错误修复)

问题:当任何密钥的缓存过期时,以下所有调用以获取缓存中的任何对象都将返回“null”.我检查钥匙,总是正确的.

问题仅发生在我的PC中的客户端服务器中,并且我的服务器工作正常.

谢谢.

编辑II(进展)

当我们在客户的服务器中重新启动应用程序池时,您的问题将在几个小时内解决.

我们的网站有一个特定的应用程序池,具有以下设置:

管道管理器模式:集成
框架:v4.0
启用32位应用程序:True.

其他设置,如默认.

在服务器上,我们有2个站点,一个启用了“启用32位应用程序”,如果两个站点都被禁用,则发生错误,但不知道这是否是问题.

编辑III(进展)

由于我们未能解决问题,我们决定切换到Httpcontext.Current.Cache,我们可以解决问题.我们想要另一种解决方案并继续使用MemoryCache,但没有结果.

解决方法

复活一个旧问题,但我认为这个问题是由于一个只在ASP.NET 4.5中修复的错误,但是对于早期版本有一个修补程序.

见这个帖子:MemoryCache Empty : Returns null after being set

.NET Core Cache [MemoryCache]

.NET Core Cache [MemoryCache]

参考资料:long0801的博客、MemoryCache微软官方文档

添加对Microsoft.Extensions.Caching.Memory命名空间的引用,它提供了.NET Core默认实现的MemoryCache类,以及全新的内存缓存API

代码如下:

using System;
using Microsoft.Extensions.Caching.Memory;

namespace FrameWork.Common.DotNetCache
{
    public class CacheHelper
    {
        static readonly MemoryCache Cache = new MemoryCache(new MemoryCacheOptions());

        /// <summary>
        /// 获取缓存中的值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static object GetCacheValue(string key)
        {
            if ( !string.IsNullOrEmpty(key) && Cache.TryGetValue(key, out var val))
            {
                return val;
            }
            return default(object);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public static void SetCacheValue(string key, object value)
        {
            if (!string.IsNullOrEmpty(key))
            {
                Cache.Set(key, value, new MemoryCacheEntryOptions
                {
                    SlidingExpiration = TimeSpan.FromHours(1)
                });
            }
        }
    }
}

 

.Net Core MemoryCache PostEvictionCallback无法正常工作

.Net Core MemoryCache PostEvictionCallback无法正常工作

我在Microsoft.Extensions.Caching.Memory.MemoryCache中设置了具有滑动过期的缓存项.
我想在每次缓存项到期时触发回调,但在我查询缓存中过期的缓存项之前,不会触发回调.

这是代码:

using System;
using Microsoft.Extensions.Caching.Memory;

namespace Memcache
{
    public class Program
    {
        private static MemoryCache _cache;
        private static int _cacheExpSecs;

        public static void Main(string[] args)
        {
            _cache = new MemoryCache(new MemoryCacheOptions());
            _cacheExpSecs = 2;

            var cacheEntryOptions = new MemoryCacheEntryOptions()
            .SetSlidingExpiration(TimeSpan.FromSeconds(_cacheExpSecs))
            .RegisterPostevictionCallback(callback: evictionCallback);

            _cache.Set(1,"One",cacheEntryOptions);
            _cache.Set(2,"Two",cacheEntryOptions);

            var autoEvent = new System.Threading.AutoResetEvent(false);

            System.Threading.Timer timer = new System.Threading.Timer(checkCache,autoEvent,1000,6000);

            Console.Read();
        }

        private static void checkCache(Object o)
        {
            if(_cache.Get(1)!=null)
            {
                Console.WriteLine(string.Format(@"checkCache: Cache with key {0} will be removed manually and will trigger the callback.",1));
                _cache.Remove(1);
            }
            else
            {
                Console.WriteLine(string.Format("checkCache: Cache with key {0} is expired.",1));
            }


            if(_cache.Get(2) != null)
            {
                Console.WriteLine(string.Format("checkCache: Cache with key {0} will expire in {1} seconds,but won't trigger the callback until we check it's value again.",2,_cacheExpSecs));
            }
            else
            {
                Console.WriteLine(string.Format("checkCache: Cache with key {0} is expired.",2));
            }

        }

        private static void evictionCallback(object key,object value,evictionReason reason,object state)
        {
            Console.WriteLine();
            Console.WriteLine("/*****************************************************/");
            Console.WriteLine(string.Format("/*  evictionCallback: Cache with key {0} has expired.  */",key));
            Console.WriteLine("/*****************************************************/");
            Console.WriteLine();
        }
    }
}

解决方法

这种情况正在发生,因为在您查询该项目并检查到期时,该项目不会被逐出

(来自MemoryCacheStore.Get(MemoryCacheKey key)的来源)

internal MemoryCacheEntry Get(MemoryCacheKey key) {
        MemoryCacheEntry entry = _entries[key] as MemoryCacheEntry;
        // has it expired?
        if (entry != null && entry.UtcAbsExp <= DateTime.UtcNow) {
            Remove(key,entry,CacheEntryRemovedReason.Expired);
            entry = null;
        }
        // update outside of lock
        UpdateExpAndUsage(entry);
        return entry;
    }

或者由于记忆压力而在内部调用Trim()

(来自TrimInternal(int percent)的来源)

/*SNIP*/
        trimmedOrExpired = _expires.FlushExpiredItems(true);
        if (trimmedOrExpired < toTrim) {
            trimmed = _usage.FlushUnderUsedItems(toTrim - trimmedOrExpired);
            trimmedOrExpired += trimmed;
        }
/*SNIP*/

如果您的系统当前内存不足以触发修剪,那么唯一可以驱逐项目的时间是尝试检索它们的时间.

.net core MemoryCache缓存

.net core MemoryCache缓存

/// <summary>
    /// 缓存帮助类
    /// </summary>
    public class MemoryCacheHelper
    {
        private static readonly MemoryCache Cache = new MemoryCache(new MemoryCacheOptions());

        /// <summary>
        /// 验证缓存项是否存在
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns></returns>
        public static bool Exists(string key)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));
            return Cache.TryGetValue(key, out _);
        }

        /// <summary>
        /// 添加缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">缓存Value</param>
        /// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
        /// <param name="expiressAbsoulte">绝对过期时长</param>
        /// <returns></returns>
        public static bool Set(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));
            if (value == null)
                throw new ArgumentNullException(nameof(value));

            Cache.Set(key, value,
                new MemoryCacheEntryOptions().SetSlidingExpiration(expiresSliding)
                    .SetAbsoluteExpiration(expiressAbsoulte));
            return Exists(key);
        }

        /// <summary>
        /// 添加缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">缓存Value</param>
        /// <param name="expiresIn">缓存时长</param>
        /// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
        /// <returns></returns>
        public static bool Set(string key, object value, TimeSpan expiresIn, bool isSliding = false)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));
            if (value == null)
                throw new ArgumentNullException(nameof(value));

            Cache.Set(key, value,
                isSliding
                    ? new MemoryCacheEntryOptions().SetSlidingExpiration(expiresIn)
                    : new MemoryCacheEntryOptions().SetAbsoluteExpiration(expiresIn));

            return Exists(key);
        }

        #region 删除缓存

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns></returns>
        public static void Remove(string key)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));

            Cache.Remove(key);
        }

        /// <summary>
        /// 批量删除缓存
        /// </summary>
        /// <returns></returns>
        public static void RemoveAll(IEnumerable<string> keys)
        {
            if (keys == null)
                throw new ArgumentNullException(nameof(keys));

            keys.ToList().ForEach(item => Cache.Remove(item));
        }
        #endregion

        #region 获取缓存

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns></returns>
        public static T Get<T>(string key) where T : class
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));

            return Cache.Get(key) as T;
        }

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <returns></returns>
        public static object Get(string key)
        {
            if (key == null)
                throw new ArgumentNullException(nameof(key));

            return Cache.Get(key);
        }

        /// <summary>
        /// 获取缓存集合
        /// </summary>
        /// <param name="keys">缓存Key集合</param>
        /// <returns></returns>
        public static IDictionary<string, object> GetAll(IEnumerable<string> keys)
        {
            if (keys == null)
                throw new ArgumentNullException(nameof(keys));

            var dict = new Dictionary<string, object>();
            keys.ToList().ForEach(item => dict.Add(item, Cache.Get(item)));
            return dict;
        }
        #endregion

        /// <summary>
        /// 删除所有缓存
        /// </summary>
        public static void RemoveCacheAll()
        {
            var l = GetCacheKeys();
            foreach (var s in l)
            {
                Remove(s);
            }
        }

        /// <summary>
        /// 删除匹配到的缓存
        /// </summary>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public static void RemoveCacheRegex(string pattern)
        {
            IList<string> l = SearchCacheRegex(pattern);
            foreach (var s in l)
            {
                Remove(s);
            }
        }

        /// <summary>
        /// 搜索 匹配到的缓存
        /// </summary>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public static IList<string> SearchCacheRegex(string pattern)
        {
            var cacheKeys = GetCacheKeys();
            var l = cacheKeys.Where(k => Regex.IsMatch(k, pattern)).ToList();
            return l.AsReadOnly();
        }

        /// <summary>
        /// 获取所有缓存键
        /// </summary>
        /// <returns></returns>
        public static List<string> GetCacheKeys()
        {
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
            var entries = Cache.GetType().GetField("_entries", flags).GetValue(Cache);
            var cacheItems = entries as IDictionary;
            var keys = new List<string>();
            if (cacheItems == null) return keys;
            foreach (DictionaryEntry cacheItem in cacheItems)
            {
                keys.Add(cacheItem.Key.ToString());
            }
            return keys;
        }

    }

 

.Net Core 中 MemoryCache 使用

.Net Core 中 MemoryCache 使用

1.Demoemo,实际项目中不这么使用

class Program
    {
        static void Main(string[] args)
        {
            //缓存的配置
            MemoryCacheOptions cacheOps = new MemoryCacheOptions()
            {
                //缓存最大为100份
                //##注意netcore中的缓存是没有单位的,缓存项和缓存的相对关系
                SizeLimit = 100,
                //缓存满了时,压缩20%(即删除20份优先级低的缓存项)
                CompactionPercentage = 0.2,
                //两秒钟查找一次过期项
                ExpirationScanFrequency = TimeSpan.FromSeconds(3)
            };
            MemoryCache myCache = new MemoryCache(cacheOps);

            //单个缓存项的配置
            MemoryCacheEntryOptions cacheEntityOps = new MemoryCacheEntryOptions()
            {
                //绝对过期时间1
                //AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(2)),
                //绝对过期时间2
                //AbsoluteExpirationRelativeToNow=TimeSpan.FromSeconds(3),
                //相对过期时间
                SlidingExpiration = TimeSpan.FromSeconds(3),
                //优先级,当缓存压缩时会优先清除优先级低的缓存项
                Priority = CacheItemPriority.Low,//Low,Normal,High,NeverRemove
                //缓存大小占1份
                Size = 1
            };
            //注册缓存项被清除时的回调,可以注册多个回调
            cacheEntityOps.RegisterPostEvictionCallback((key, value, reason, state) =>
            {
                Console.WriteLine($"回调函数输出【键:{key},值:{value},被清除的原因:{reason}】");
            });

            myCache.Set("mykey", "myvalue", cacheEntityOps);
            Console.WriteLine($"mykey的值:{myCache.Get("mykey") ?? "mykey缓存被清除了"}");
            Console.WriteLine("------------------暂停3秒");
            Thread.Sleep(3000);
            Console.WriteLine($"mykey的值:{myCache.Get("mykey") ?? "mykey缓存被清除了"}");

            Console.ReadKey();
        }
    }
}

 

关于c# – MemoryCache在第一次到期后总是返回“null”c# memorypool的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于.NET Core Cache [MemoryCache]、.Net Core MemoryCache PostEvictionCallback无法正常工作、.net core MemoryCache缓存、.Net Core 中 MemoryCache 使用的相关信息,请在本站寻找。

本文标签: