在现代C#开发中,性能优化已经成为高级开发者必备技能。今天我们来深入探讨延迟加载这一重要设计模式,它能帮助你的应用程序在处理大量数据时保持高效运行。
延迟加载(Lazy Loading)是一种智能资源管理模式,核心思想是"用时再加载"。想象一下,你在看新闻App时,并不需要一次性加载所有文章内容,而是滑动到哪里加载到哪里。这就是延迟加载的精髓。
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}] 程序结束");
}
}
}

对于复杂业务场景,我们可以创建自定义的延迟加载容器:
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}");
}
}
}

延迟加载是C# .NET Core开发中的重要性能优化技术,掌握以下要点:
合理运用延迟加载,能让你的应用程序在处理大规模数据时依然保持出色的性能表现。
关注我,获取更多C# .NET开发实战技巧!
#C# #DotNET #性能优化 #编程技巧 #软件开发
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!