掌握 C# 延迟加载,提升性能与资源管理

81 阅读3分钟

什么是延迟加载?

延迟加载是一种设计模式,指的是在需要时才加载或初始化资源,而不是在程序启动时一次性加载所有资源。这种技术可以显著减少初始加载时间,并优化内存使用。

这种技术可以帮助提高应用程序的性能和资源利用效率。

延迟加载的主要优点

减少内存消耗

提高应用程序启动速度

按需加载资源

降低系统开销

C#中的延迟加载实现方式

使用 Lazy 类

Lazy< T>是.NET Framework 4.0引入的泛型类,提供了最简单的延迟加载实现。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AppLazy
{
    publicclass UserProfile
    {
        // 延迟加载的复杂对象  
        // ThreadSafetyMode.ExecutionAndPublication 确保线程安全  
        private Lazy<ExpensiveResource> _expensiveResource;

        public UserProfile()
        {
            // 使用 LazyThreadSafetyMode 确保线程安全  
            _expensiveResource = new Lazy<ExpensiveResource>(
                () => new ExpensiveResource(),
                LazyThreadSafetyMode.ExecutionAndPublication
            );
        }

        public ExpensiveResource GetResource()
        {
            // 只有在调用Value时才真正创建对象  
            return _expensiveResource.Value;
        }
    }

    publicclass ExpensiveResource
    {
        public Guid ResourceId { get; } = Guid.NewGuid();

        public ExpensiveResource()
        {
            // 模拟复杂的初始化过程  
            Console.WriteLine($"正在初始化复杂资源 {ResourceId}...");
            Thread.Sleep(2000); // 模拟耗时操作  
            Console.WriteLine($"复杂资源 {ResourceId} 初始化完成。");
        }
    }
}
namespace AppLazy
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建 UserProfile 实例  
            UserProfile userProfile = new UserProfile();

            Console.WriteLine("创建 UserProfile 实例,但尚未初始化资源...");

            // 第一次访问 ExpensiveResource  
            Console.WriteLine("第一次获取资源:");
            ExpensiveResource resource1 = userProfile.GetResource();

            // 再次访问,不会重复初始化  
            Console.WriteLine("第二次获取资源:");
            ExpensiveResource resource2 = userProfile.GetResource();

            // 验证是否是同一个实例  
            Console.WriteLine($"两次获取的资源是否是同一个实例:{object.ReferenceEquals(resource1, resource2)}");
        }
    }
}

延迟加载集合

namespace AppLazy
{
    publicclass LazyCollection
    {
        // 使用Lazy<List<T>>延迟加载集合  
        private Lazy<List<string>> _lazyItems;

        public LazyCollection()
        {
            _lazyItems = new Lazy<List<string>>(() => LoadItems());
        }

        private List<string> LoadItems()
        {
            Console.WriteLine("正在加载数据集合...");
           
           // 模拟耗时的数据加载过程,比如从数据库或文件中读取  
            System.Threading.Thread.Sleep(1000); 
            // 模拟1秒加载时间  
            returnnew List<string> { "Item1", "Item2", "Item3" };
        }

        public List<string> GetItems()
        {
            return _lazyItems.Value;
        }

        public static void Main(string[] args)
        {
            LazyCollection collection = new LazyCollection();

            Console.WriteLine("创建集合实例,但尚未加载数据...");

            // 第一次访问时会触发数据加载  
            Console.WriteLine("第一次获取数据:");
            List<string> items = collection.GetItems();
            foreach (var item in items)
            {
                Console.WriteLine(item);
            }

            // 再次获取数据(不会重复加载)  
            Console.WriteLine("\n第二次获取数据:");
            items = collection.GetItems();
            foreach (var item in items)
            {
                Console.WriteLine(item);
            }
        }
    }
}

自定义延迟加载实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AppLazy
{
    // 定义一个演示用的类  
    publicclass ExpensiveResource
    {
        public Guid Id { get; privateset; }
        public DateTime CreatedAt { get; privateset; }

        public ExpensiveResource()
        {
            Id = Guid.NewGuid();
            CreatedAt = DateTime.Now;
            Console.WriteLine
            ($"ExpensiveResource 实例被创建,ID: {Id}");
        }

        public void DoSomething()
        {
            Console.WriteLine
            ($"正在使用资源 {Id}");
        }
    }
}
namespace AppLazy
{
    publicclass Program
    {
        public static void Main(string[] args)
        {
            // 创建一个CustomLazyLoader实例  
            CustomLazyLoader<ExpensiveResource> lazyLoader =
            new CustomLazyLoader<ExpensiveResource>();

            Console.WriteLine("准备获取实例...");

            // 第一次调用会创建实例  
            ExpensiveResource resource1 = lazyLoader.GetInstance();
            resource1.DoSomething();

            Console.WriteLine("再次获取实例...");

            // 第二次调用会返回同一个实例  
            ExpensiveResource resource2 = lazyLoader.GetInstance();
            resource2.DoSomething();

            // 验证两次获取的是同一个实例  
            Console.WriteLine
            ($"两次获取的实例是否相同:{ReferenceEquals(resource1, resource2)}");
        }
    }

    // 自定义延迟加载器  
    publicclass CustomLazyLoader<T> where T :new()
    {
        private T _instance;
        privatebool _isInitialized = false;
        private readonly object _lock = new object();

        public T GetInstance()
        {
            // 线程安全的双重检查锁定模式  
            if (!_isInitialized)
            {
                lock (_lock)
                {
                    if (!_isInitialized)
                    {
                        _instance = new T();
                        _isInitialized = true;
                    }
                }
            }
            return _instance;
        }
    }
}

实际应用场景

数据库查询延迟加载

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AppLazy
{
    // 用户实体类  
    publicclass User
    {
        publicint Id { get; set; }
        publicstring Username { get; set; }
        publicstring Email { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LiteDB;

namespace AppLazy
{
    publicclass UserRepository : IDisposable
    {
        private readonly string _dbPath;
        private readonly object _lock = new object();

        public UserRepository(string dbPath = "users.db")
        {
            _dbPath = dbPath;
        }

        private LiteDatabase CreateDatabaseConnection()
        {
            try
            {
                // 直接使用路径,不再使用 ConnectionString  
                returnnew LiteDatabase(_dbPath);
            }
            catch (IOException ex)
            {
                Console.WriteLine($"数据库连接错误: {ex.Message}");
                throw;
            }
        }

        // 修改所有数据库操作方法  
        public List<User> FetchUsersFromDatabase()
        {
            lock (_lock)
            {
                using (var database = CreateDatabaseConnection())
                {
                    var collection = database.GetCollection<User>("users");
                    returnnew List<User>(collection.FindAll());
                }
            }
        }

        public void AddUser(User user)
        {
            lock (_lock)
            {
                using (var database = CreateDatabaseConnection())
                {
                    var collection = database.GetCollection<User>("users");
                    collection.Insert(user);
                }
            }
        }

        public User GetUserById(int id)
        {
            lock (_lock)
            {
                using (var database = CreateDatabaseConnection())
                {
                    var collection = database.GetCollection<User>("users");
                    return collection.FindById(id);
                }
            }
        }

        public void Dispose()
        {
            // 如果需要额外的清理逻辑,可以在这里添加  
            GC.SuppressFinalize(this);
        }
    }
}

调用

namespace AppLazy
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (var repository = new UserRepository())
                {
                    // 添加用户  
                    repository.AddUser(new User
                    {
                        Username = "john_doe",
                        Email = "john@example.com"
                    });

                    // 获取所有用户  
                    var users = repository.FetchUsersFromDatabase();
                    foreach (var user in users)
                    {
                        Console.WriteLine($"User: {user.Username}, Email: {user.Email}");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误: {ex.Message}");
            }
        }
    }
}

注意

对于计算成本高的对象使用延迟加载

使用 Lazy 处理线程安全问题

避免在性能关键路径上使用复杂的延迟加载逻辑

不要过度使用延迟加载

考虑线程安全性

评估初始化成本

注意内存管理

总结

延迟加载是一种强大的技术,可以显著优化应用程序的性能和资源利用。通过谨慎和有策略地应用,可以帮助开发者创建更高效、更响应迅速的应用程序。

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:技术老小子

出处:mp.weixin.qq.com/s/hpxy2SBGN1mLxCvPLEs8lg

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!