You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MemoryCache的CacheItemPolicy仅在固定20秒边界过期问题问询

MemoryCache过期粒度问题的解决思路

问题说明

之前靠Ben Hall的方案搞定了FileSystemWatcher事件重复触发的问题,但现在碰到个新麻烦:用CacheItemPolicy设置了AbsoluteExpiration或SlidingExpiration的MemoryCache,根本不按设定的时间过期,只会在固定的20秒时间点(比如整分的:00、:20、:40)触发过期回调。举个例子,我设置绝对过期为当前时间加100毫秒,结果回调OnRemoveFromCache要等到下一个20秒边界才执行——比如事件12:34:05.000触发,回调12:34:20.000才跑起来。查了才知道,这是MemoryCache本身的过期粒度就是20秒导致的,现在想找个类似模式但粒度更细的替代方案,或者是不是得自己实现一个?

可行方案

1. 换用官方的ASP.NET Core内存缓存

直接用Microsoft.Extensions.Caching.Memory,这是ASP.NET Core里的内存缓存实现,支持毫秒级的过期精度,API和传统MemoryCache差不多,迁移成本很低。用MemoryCacheEntryOptions设置AbsoluteExpirationRelativeToNow或者SlidingExpiration,回调能精准触发,完全满足需求。

2. 用第三方缓存库

比如CacheManager,这是个开源的缓存抽象库,支持多种缓存后端,内存缓存模式下可以配置更细的过期检查间隔,轻松实现毫秒级的过期触发。

3. 自己写个轻量级缓存

要是不想加第三方依赖,自己写个简单的也不难:

  • 用字典存缓存项,每个项记录键、值、过期时间和回调函数。
  • 启动一个后台定时任务(比如用Timer或者循环Task.Delay),每隔几毫秒检查一次缓存项,到过期时间就触发回调并移除。
  • 注意线程安全,操作字典的时候加锁就行。

给个简单的示例代码:

public class PreciseCache
{
    private readonly Dictionary<string, CacheEntry> _cacheStore = new();
    private readonly object _lock = new();
    private readonly Timer _cleanupTimer;

    public PreciseCache(int checkIntervalMs = 10)
    {
        _cleanupTimer = new Timer(CleanupExpiredEntries, null, 0, checkIntervalMs);
    }

    public void Add(string key, object value, TimeSpan absoluteExpiration, Action<string, object> onExpireCallback)
    {
        lock (_lock)
        {
            _cacheStore[key] = new CacheEntry
            {
                Value = value,
                ExpiresAt = DateTime.UtcNow.Add(absoluteExpiration),
                OnExpire = onExpireCallback
            };
        }
    }

    private void CleanupExpiredEntries(object state)
    {
        var now = DateTime.UtcNow;
        List<string> expiredKeys;

        lock (_lock)
        {
            expiredKeys = _cacheStore.Where(kv => kv.Value.ExpiresAt <= now).Select(kv => kv.Key).ToList();
        }

        foreach (var key in expiredKeys)
        {
            lock (_lock)
            {
                if (_cacheStore.TryRemove(key, out var entry))
                {
                    entry.OnExpire?.Invoke(key, entry.Value);
                }
            }
        }
    }

    private class CacheEntry
    {
        public object Value { get; set; }
        public DateTime ExpiresAt { get; set; }
        public Action<string, object> OnExpire { get; set; }
    }
}

4. 别碰修改MemoryCache内部参数的方案

有人可能会想通过反射改MemoryCache的过期检查间隔,但这属于黑科技,完全依赖内部实现,.NET版本一更新就可能失效,生产环境绝对别用。

总结

优先选Microsoft.Extensions.Caching.Memory,官方维护靠谱,精度够还不用改太多代码;其次考虑第三方库;实在不行自己写个轻量级的也简单。

内容的提问来源于stack exchange,提问作者lmattcris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 08:21:57