LazyCache源码解析:Lazy 与IMemoryCache的完美结合
LazyCache是一个简单易用的线程安全内存缓存服务,为C#开发者提供友好的API接口。它巧妙地结合了Lazy 延迟加载机制与IMemoryCache缓存功能,在保证高性能的同时简化了缓存逻辑的实现。本文将深入剖析LazyCache的核心设计理念与实现细节,帮助开发者理解其内部工作原理。
核心架构:Lazy 与IMemoryCache的融合
LazyCache的核心优势在于将Lazy 的延迟初始化特性与IMemoryCache的缓存管理能力无缝结合。这种组合不仅减少了不必要的计算开销,还确保了多线程环境下的安全性。
在LazyCache的实现中,LazyCache/CachingService.cs是核心类,它通过GetValueFromLazy<T>和GetValueFromAsyncLazy<T>方法处理缓存项的获取逻辑:
protected virtual T GetValueFromLazy<T>(object item, out bool valueHasChangedType)
{
valueHasChangedType = false;
switch (item)
{
case Lazy<T> lazy:
return lazy.Value;
case AsyncLazy<T> asyncLazy:
valueHasChangedType = true;
return asyncLazy.GetAwaiter().GetResult();
default:
valueHasChangedType = true;
return (T)item;
}
}
这段代码展示了LazyCache如何处理不同类型的缓存项,特别是Lazy 和AsyncLazy 类型,实现了延迟加载与缓存的完美结合。
缓存提供器:基于IMemoryCache的实现
LazyCache使用IMemoryCache作为底层缓存存储,通过LazyCache/Providers/MemoryCacheProvider.cs封装了缓存的基本操作:
internal readonly IMemoryCache cache;
public MemoryCacheProvider(IMemoryCache cache)
{
this.cache = cache ?? throw new ArgumentNullException(nameof(cache));
}
这种设计使得LazyCache可以轻松集成到ASP.NET Core应用中,通过依赖注入配置缓存服务。在LazyCache.AspNetCore/LazyCacheServiceCollectionExtensions.cs中可以看到服务注册的实现:
services.TryAdd(ServiceDescriptor.Singleton<IMemoryCache, MemoryCache>());
核心API:GetOrAdd方法解析
LazyCache提供的GetOrAdd方法是其最核心的API之一,它实现了"如果缓存存在则获取,不存在则添加"的逻辑,同时利用Lazy
确保了只有一个线程会执行创建逻辑。
在LazyCache/IAppCache.cs中定义了GetOrAdd方法的接口:
T GetOrAdd<T>(string key, Func<ICacheEntry, T> addItemFactory);
Task<T> GetOrAddAsync<T>(string key, Func<ICacheEntry, Task<T>> addItemFactory);
而在LazyCache/CachingService.cs中的实现则展示了如何结合Lazy 和IMemoryCache:
public virtual T GetOrAdd<T>(string key, Func<ICacheEntry, T> addItemFactory)
{
return GetOrAdd(key, addItemFactory, null);
}
实际的缓存项创建逻辑使用了Lazy 来包装:
new Lazy<T>(() =>
{
var entry = cacheProvider.CreateEntry(key);
// ... 设置缓存策略
var result = addItemFactory(entry);
entry.SetValue(result);
return result;
})
这种设计确保了即使在高并发场景下,昂贵的创建操作也只会执行一次。
异步支持:AsyncLazy 的实现
LazyCache对异步操作提供了一流的支持,通过LazyCache/AsyncLazy.cs实现了异步版本的延迟加载:
public class AsyncLazy<T> : Lazy<Task<T>>
AsyncLazy
类继承自Lazy<Task
>,结合了延迟初始化和异步编程模型。在CachingService中,
GetOrAddAsync方法使用AsyncLazy
来处理异步缓存项的创建:
new AsyncLazy<T>(async () =>
{
var entry = cacheProvider.CreateEntry(key);
// ... 设置缓存策略
var result = await addItemFactory(entry).ConfigureAwait(false);
entry.SetValue(result);
return result;
})
实际应用示例
在Console.Net461/Program.cs中可以看到LazyCache的基本用法:
var item = cache.GetOrAdd("Program.Main.Person", () => Tuple.Create("Joe Blogs", DateTime.UtcNow));
而在CacheDatabaseQueriesApiSample/Controllers/DbTimeController.cs中展示了如何缓存数据库查询结果:
var cachedDatabaseTime = cache.GetOrAdd(cacheKey, actionThatWeWantToCache);
这些示例展示了LazyCache简洁易用的API设计,开发者无需关心复杂的缓存逻辑,只需专注于业务代码。
总结:LazyCache的优势与适用场景
LazyCache通过将Lazy 的延迟加载与IMemoryCache的缓存管理相结合,提供了一个高性能、线程安全且易于使用的缓存解决方案。其主要优势包括:
- 简化缓存逻辑:通过
GetOrAdd方法将缓存检查和添加逻辑合并,减少样板代码 - 线程安全:利用Lazy 确保并发环境下昂贵操作只执行一次
- 异步支持:原生支持异步操作,不会阻塞线程
- 与ASP.NET Core集成:提供了LazyCache.AspNetCore项目,可无缝集成到ASP.NET Core应用中
LazyCache特别适合需要频繁访问相同数据且数据计算或获取成本较高的场景,如数据库查询、API调用结果缓存等。通过使用LazyCache,开发者可以轻松提升应用性能,同时保持代码的简洁性和可维护性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



