2025-11-04
C#
00

目录

什么是延迟加载?
延迟加载的4大优势
实战技术一:使用Lazy<T>实现对象延迟初始化
完整示例:文件处理服务
实战技术二:自定义延迟加载容器
总结
#DotNET #性能优化 #编程技巧 #软件开发

在现代C#开发中,性能优化已经成为高级开发者必备技能。今天我们来深入探讨延迟加载这一重要设计模式,它能帮助你的应用程序在处理大量数据时保持高效运行。

什么是延迟加载?

延迟加载(Lazy Loading)是一种智能资源管理模式,核心思想是"用时再加载"。想象一下,你在看新闻App时,并不需要一次性加载所有文章内容,而是滑动到哪里加载到哪里。这就是延迟加载的精髓。

延迟加载的4大优势

  1. 内存友好:避免一次性加载大量数据造成内存压力
  2. 启动更快:应用程序初始化时间显著减少
  3. 性能提升:减少不必要的数据库查询和网络请求
  4. 用户体验优化:响应更加迅速,交互更流畅

实战技术一:使用Lazy实现对象延迟初始化

Lazy<T>是.NET框架提供的内置延迟加载解决方案,使用简单但功能强大。

完整示例:文件处理服务

C#
namespace AppLazyLoading { /// <summary> /// 模拟一个资源密集型的文件处理服务 /// </summary> public class FileProcessingService { private readonly string _configPath; public FileProcessingService(string configPath) { _configPath = configPath; Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] FileProcessingService 开始初始化..."); // 模拟耗时的初始化过程:读取配置、建立连接等 Thread.Sleep(3000); Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] FileProcessingService 初始化完成!"); } /// <summary> /// 处理文件的核心方法 /// </summary> public string ProcessFile(string fileName) { Console.WriteLine($"正在处理文件: {fileName}"); return $"文件 {fileName} 处理完成,大小:{new Random().Next(100, 1000)}KB"; } } /// <summary> /// 主程序:演示延迟加载的效果 /// </summary> class Program { // 使用 Lazy<T> 包装服务,实现延迟初始化 // 线程安全的单例模式 private static readonly Lazy<FileProcessingService> _lazyFileService = new Lazy<FileProcessingService>(() => new FileProcessingService("config.xml")); static void Main(string[] args) { Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 程序启动"); Console.WriteLine("================================"); // 程序启动时,服务并未实例化 Console.WriteLine("程序已启动,但文件服务尚未初始化"); // 模拟其他业务逻辑 Thread.Sleep(2000); Console.WriteLine("\n现在需要使用文件服务..."); // 第一次访问 Value 属性时,才开始真正的初始化 var result = _lazyFileService.Value.ProcessFile("document.pdf"); Console.WriteLine($"处理结果: {result}"); // 再次使用时,不会重复初始化 Console.WriteLine("\n再次使用服务(无需重复初始化):"); var result2 = _lazyFileService.Value.ProcessFile("image.jpg"); Console.WriteLine($"处理结果: {result2}"); Console.WriteLine($"\n[{DateTime.Now:HH:mm:ss}] 程序结束"); } } }

image.png

实战技术二:自定义延迟加载容器

对于复杂业务场景,我们可以创建自定义的延迟加载容器:

C#
using System; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; namespace CustomLazyLoading { /// <summary> /// 支持异步操作的延迟加载容器 /// </summary> public class AsyncLazy<T> { private readonly Func<Task<T>> _taskFactory; private readonly Lazy<Task<T>> _lazy; public AsyncLazy(Func<Task<T>> taskFactory) { _taskFactory = taskFactory ?? throw new ArgumentNullException(nameof(taskFactory)); _lazy = new Lazy<Task<T>>(taskFactory); } /// <summary> /// 获取异步任务 /// </summary> public Task<T> Value => _lazy.Value; /// <summary> /// 检查是否已经开始加载 /// </summary> public bool IsValueCreated => _lazy.IsValueCreated; /// <summary> /// 重置延迟加载状态(重新创建Lazy实例) /// </summary> public void Reset() { if (_lazy.IsValueCreated) { // 这里需要重新创建一个新的AsyncLazy实例来实现真正的重置 // 或者可以考虑其他设计模式 } } } /// <summary> /// 支持取消的异步延迟加载容器 /// </summary> public class CancellableAsyncLazy<T> { private readonly Func<CancellationToken, Task<T>> _taskFactory; private readonly object _lock = new object(); private Task<T> _task; public CancellableAsyncLazy(Func<CancellationToken, Task<T>> taskFactory) { _taskFactory = taskFactory ?? throw new ArgumentNullException(nameof(taskFactory)); } public Task<T> GetValue(CancellationToken cancellationToken = default) { if (_task != null) return _task; lock (_lock) { if (_task == null) { _task = _taskFactory(cancellationToken); } return _task; } } public bool IsValueCreated => _task != null; public void Reset() { lock (_lock) { _task = null; } } } /// <summary> /// 使用示例:异步数据服务 /// </summary> public class DataService { private readonly AsyncLazy<string> _lazyData; private readonly AsyncLazy<List<User>> _lazyUsers; private readonly CancellableAsyncLazy<string> _cancellableLazyConfig; public DataService() { // 延迟加载异步数据 _lazyData = new AsyncLazy<string>(LoadDataAsync); // 延迟加载用户列表 _lazyUsers = new AsyncLazy<List<User>>(LoadUsersAsync); // 支持取消的延迟加载配置 _cancellableLazyConfig = new CancellableAsyncLazy<string>(LoadConfigAsync); } /// <summary> /// 模拟异步数据加载(如API调用、文件读取等) /// </summary> private async Task<string> LoadDataAsync() { Console.WriteLine("开始异步加载数据..."); // 模拟网络请求或文件I/O await Task.Delay(2000); Console.WriteLine("数据加载完成!"); return "这是从远程API获取的重要数据"; } /// <summary> /// 模拟加载用户列表 /// </summary> private async Task<List<User>> LoadUsersAsync() { Console.WriteLine("开始加载用户列表..."); await Task.Delay(1500); var users = new List<User> { new User { Id = 1, Name = "张三", Email = "zhangsan@example.com" }, new User { Id = 2, Name = "李四", Email = "lisi@example.com" }, new User { Id = 3, Name = "王五", Email = "wangwu@example.com" } }; Console.WriteLine($"用户列表加载完成,共{users.Count}个用户"); return users; } /// <summary> /// 支持取消的配置加载 /// </summary> private async Task<string> LoadConfigAsync(CancellationToken cancellationToken) { Console.WriteLine("开始加载配置..."); // 模拟长时间的配置加载过程 for (int i = 0; i < 10; i++) { cancellationToken.ThrowIfCancellationRequested(); await Task.Delay(300, cancellationToken); Console.WriteLine($"配置加载进度: {(i + 1) * 10}%"); } Console.WriteLine("配置加载完成!"); return "重要的系统配置数据"; } /// <summary> /// 获取数据 /// </summary> public async Task<string> GetDataAsync() { return await _lazyData.Value; } /// <summary> /// 获取用户列表 /// </summary> public async Task<List<User>> GetUsersAsync() { return await _lazyUsers.Value; } /// <summary> /// 获取配置(支持取消) /// </summary> public async Task<string> GetConfigAsync(CancellationToken cancellationToken = default) { return await _cancellableLazyConfig.GetValue(cancellationToken); } /// <summary> /// 检查数据是否已加载 /// </summary> public bool IsDataLoaded => _lazyData.IsValueCreated; /// <summary> /// 检查用户列表是否已加载 /// </summary> public bool IsUsersLoaded => _lazyUsers.IsValueCreated; /// <summary> /// 检查配置是否已加载 /// </summary> public bool IsConfigLoaded => _cancellableLazyConfig.IsValueCreated; /// <summary> /// 重置配置加载状态 /// </summary> public void ResetConfig() { _cancellableLazyConfig.Reset(); Console.WriteLine("配置加载状态已重置"); } } /// <summary> /// 用户模型 /// </summary> public class User { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public override string ToString() { return $"User(Id: {Id}, Name: {Name}, Email: {Email})"; } } /// <summary> /// 高级异步延迟加载示例:缓存服务 /// </summary> public class CacheService { private readonly Dictionary<string, AsyncLazy<object>> _cache = new(); private readonly object _lock = new object(); /// <summary> /// 获取或创建缓存项 /// </summary> public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory) { AsyncLazy<object> lazy; lock (_lock) { if (!_cache.TryGetValue(key, out lazy)) { lazy = new AsyncLazy<object>(async () => await factory()); _cache[key] = lazy; } } var result = await lazy.Value; return (T)result; } /// <summary> /// 检查缓存项是否存在且已加载 /// </summary> public bool IsLoaded(string key) { lock (_lock) { return _cache.TryGetValue(key, out var lazy) && lazy.IsValueCreated; } } /// <summary> /// 移除缓存项 /// </summary> public void Remove(string key) { lock (_lock) { _cache.Remove(key); } } /// <summary> /// 清空所有缓存 /// </summary> public void Clear() { lock (_lock) { _cache.Clear(); } } } /// <summary> /// 程序入口点,演示各种用法 /// </summary> class Program { static async Task Main(string[] args) { Console.WriteLine("=== 异步延迟加载示例 ===\n"); // 1. 基本用法演示 await BasicUsageDemo(); Console.WriteLine("\n" + new string('=', 50) + "\n"); // 2. 取消操作演示 await CancellationDemo(); Console.WriteLine("\n" + new string('=', 50) + "\n"); // 3. 缓存服务演示 await CacheServiceDemo(); Console.WriteLine("\n程序执行完成,按任意键退出..."); Console.ReadKey(); } /// <summary> /// 基本用法演示 /// </summary> static async Task BasicUsageDemo() { Console.WriteLine("1. 基本用法演示"); Console.WriteLine("================"); var dataService = new DataService(); // 检查初始状态 Console.WriteLine($"数据加载状态: {dataService.IsDataLoaded}"); Console.WriteLine($"用户列表加载状态: {dataService.IsUsersLoaded}"); // 并发获取数据 - 方法1:分别等待 var dataTask = dataService.GetDataAsync(); var usersTask = dataService.GetUsersAsync(); // 等待所有任务完成 await Task.WhenAll(dataTask, usersTask); // 获取结果 var data = await dataTask; var users = await usersTask; Console.WriteLine($"\n获取到的数据: {data}"); Console.WriteLine($"用户列表:"); foreach (var user in users) { Console.WriteLine($" - {user}"); } // 再次检查状态 Console.WriteLine($"\n数据加载状态: {dataService.IsDataLoaded}"); Console.WriteLine($"用户列表加载状态: {dataService.IsUsersLoaded}"); // 第二次调用应该立即返回缓存的结果 Console.WriteLine("\n第二次调用(应该立即返回):"); var cachedData = await dataService.GetDataAsync(); Console.WriteLine($"缓存的数据: {cachedData}"); } /// <summary> /// 取消操作演示 /// </summary> static async Task CancellationDemo() { Console.WriteLine("2. 取消操作演示"); Console.WriteLine("================"); var dataService = new DataService(); // 创建取消令牌 using var cts = new CancellationTokenSource(); // 3秒后自动取消 cts.CancelAfter(TimeSpan.FromSeconds(3)); try { Console.WriteLine("开始加载配置(3秒后自动取消)..."); var config = await dataService.GetConfigAsync(cts.Token); Console.WriteLine($"获取到配置: {config}"); } catch (OperationCanceledException) { Console.WriteLine("配置加载被取消"); } // 重置并重新尝试 Console.WriteLine("\n重置配置加载状态并重新尝试..."); dataService.ResetConfig(); try { var config = await dataService.GetConfigAsync(); Console.WriteLine($"重新获取的配置: {config}"); } catch (Exception ex) { Console.WriteLine($"配置加载失败: {ex.Message}"); } } /// <summary> /// 缓存服务演示 /// </summary> static async Task CacheServiceDemo() { Console.WriteLine("3. 缓存服务演示"); Console.WriteLine("================"); var cacheService = new CacheService(); // 定义一些异步工厂方法 Func<Task<string>> expensiveOperation1 = async () => { Console.WriteLine("执行昂贵操作1..."); await Task.Delay(1000); return "昂贵操作1的结果"; }; Func<Task<int>> expensiveOperation2 = async () => { Console.WriteLine("执行昂贵操作2..."); await Task.Delay(800); return 42; }; // 第一次调用 - 应该执行实际操作 Console.WriteLine("第一次调用缓存操作:"); var result1 = await cacheService.GetOrCreateAsync("key1", expensiveOperation1); var result2 = await cacheService.GetOrCreateAsync("key2", expensiveOperation2); Console.WriteLine($"结果1: {result1}"); Console.WriteLine($"结果2: {result2}"); // 检查缓存状态 Console.WriteLine($"\nkey1缓存状态: {cacheService.IsLoaded("key1")}"); Console.WriteLine($"key2缓存状态: {cacheService.IsLoaded("key2")}"); // 第二次调用 - 应该直接返回缓存结果 Console.WriteLine("\n第二次调用(应该直接返回缓存):"); var cachedResult1 = await cacheService.GetOrCreateAsync("key1", expensiveOperation1); var cachedResult2 = await cacheService.GetOrCreateAsync("key2", expensiveOperation2); Console.WriteLine($"缓存结果1: {cachedResult1}"); Console.WriteLine($"缓存结果2: {cachedResult2}"); // 清空缓存 Console.WriteLine("\n清空缓存并重新调用:"); cacheService.Clear(); var newResult = await cacheService.GetOrCreateAsync("key1", expensiveOperation1); Console.WriteLine($"清空缓存后的新结果: {newResult}"); } } }

image.png

总结

延迟加载是C# .NET Core开发中的重要性能优化技术,掌握以下要点:

  1. Lazy 适用于对象延迟初始化
  2. EF Core延迟加载 适用于数据访问优化
  3. 自定义容器 适用于复杂异步场景
  4. 避免N+1查询,注意线程安全
  5. 根据具体场景选择最适合的策略

合理运用延迟加载,能让你的应用程序在处理大规模数据时依然保持出色的性能表现。


关注我,获取更多C# .NET开发实战技巧!

#C# #DotNET #性能优化 #编程技巧 #软件开发

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!