.NET 中的延迟初始化:Lazy<T> 与LazyInitializer

标签:线程安全、延迟初始化、按需初始化、提升启动性能

项目地址:NitasDemo/12Lazy/LazyDemo at main · Nita121388/NitasDemo

目录

  • Lazy<T>
    • 1. 概念
    • 2. 基本用法
    • 3. 异常处理
    • 4. 线程安全模式
    • 5. 示例
      • 1. 线程安全模式 (`ExecutionAndPublication`)
      • 2. 发布模式 (`PublicationOnly`)
      • 3. 结合依赖注入 (DI)
    • 使用场景总结
    • 6. 注意事项与最佳实践
    • 7. 总结
  • LazyInitializer
    • 1. 概念
    • 2. 方法重载详解
    • 3. 与 Lazy<T> 的对比
    • 4. 最佳实践
    • 5. 总结
  • 选择建议
  • 总结

Lazy

官方文档:Lazy<T> 类 (System) | Microsoft Learn

源码:Lazy.cs

1. 概念

Lazy<T> 是 .NET 4.0 引入的泛型类,实现延迟初始化

它确保对象仅在首次访问时被创建,从而避免不必要的资源消耗并提升启动性能。

该类封装了延迟初始化的逻辑,并提供了线程安全的初始化机制。

  • 特性

    特性说明
    延迟初始化对象在第一次访问 `.Value` 时才被实例化,提升启动性能。
    节省资源如果对象从未被使用,则不会创建,节省内存和 CPU。
    线程安全默认支持多线程环境下的安全初始化(可设置线程安全模式)
    可复用一旦初始化完成,后续访问 `.Value` 将直接返回已创建的对象,不会重复创建。
    支持复杂逻辑可通过委托传入自定义初始化逻辑。
  • 优点

    减少启动时间,按需加载资源。

  • 缺点

    • 首次访问可能有延迟。
    • 线程安全模式存在锁竞争和异常放大,滥用会浪费性能
    • 过度使用会导致代码可读性下降。
  • 最佳实践

    仅对真正需要延迟初始化的对象使用 Lazy<T>

2. 基本用法

  • 用法1:默认构造函数(要求无参构造)

    // 简单创建(非线程安全)
    Lazy<ExpensiveObject> lazySimple = new Lazy<ExpensiveObject>();
    ExpensiveObject obj = lazySimple.Value; // 首次访问时初始化
    
  • 用法2:使用委托自定义初始化逻辑

    Lazy<MyClass> lazy = new Lazy<MyClass>(() => new MyClass("自定义构造"));
    

3. 异常处理

  • 初始化异常被缓存

    首次初始化失败后,异常会在每次调用时重新抛出。

  • 解决方案

    使用 Lazy<T> 的构造函数重载捕获异常并重试。

Lazy<ExpensiveObject> lazyWithRetry = new Lazy<ExpensiveObject>(() => 
{try { return new ExpensiveObject(); }catch { /* 重试逻辑 */ }
});

4. 线程安全模式

PublicationOnly

通过 LazyThreadSafetyMode 指定初始化行为:

  • 构造函数

    public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode);
    
    模式枚举值含义说明适用场景
    `ExecutionAndPublication`线程安全,确保只有一个线程执行初始化逻辑。多线程环境(默认)
    `PublicationOnly`多线程下允许多个线程同时初始化,但只保留第一个完成的实例。避免加锁阻塞、初始化成本高、重复初始化无影响,允许短暂浪费资源时
    `None`非线程安全单线程环境(高性能)
    • ExecutionAndPublication 模式部分源码

      private void ExecutionAndPublication(LazyHelper executionAndPublication, bool useDefaultConstructor){lock (executionAndPublication){// it's possible for multiple calls to have piled up behind the lock, so we need to check// to see if the ExecutionAndPublication object is still the current implementation.if (ReferenceEquals(_state, executionAndPublication)){if (useDefaultConstructor){ViaConstructor();}else{ViaFactory(LazyThreadSafetyMode.ExecutionAndPublication);}}}}
    • PublicationOnly模式部分源码

      private void PublicationOnly(LazyHelper publicationOnly, T possibleValue){LazyHelper? previous = Interlocked.CompareExchange(ref _state, LazyHelper.PublicationOnlyWaitForOtherThreadToPublish, publicationOnly);if (previous == publicationOnly){_factory = null;_value = possibleValue;_state = null; // volatile write, must occur after setting _value}}
      
// 线程安全模式(默认:确保仅初始化一次)
Lazy<ExpensiveObject> safeLazy = new Lazy<ExpensiveObject>(() => new ExpensiveObject(),LazyThreadSafetyMode.ExecutionAndPublication
);//避免加锁阻塞、初始化成本高、允许短暂浪费资源时,使用 PublicationOnly 
Lazy<ExpensiveCache> cache = new Lazy<ExpensiveCache>( 
() => new ExpensiveObject(), 
LazyThreadSafetyMode.PublicationOnly);// 非线程安全模式(高性能单线程场景)
Lazy<ExpensiveObject> unsafeLazy = new Lazy<ExpensiveObject>(() => new ExpensiveObject(),LazyThreadSafetyMode.None
);

5. 示例

1. 线程安全模式 (ExecutionAndPublication)

场景:全局配置加载

using System;
using System.Threading;
using System.Threading.Tasks;#region 模拟配置类 Configurationpublic class Configuration
{public string Environment { get; set; }public int MaxConnections { get; set; }public DateTime LoadTime { get; set; }public override string ToString() => $"[{Environment}] MaxConnections={MaxConnections}, LoadTime={LoadTime:HH:mm:ss.fff}";
}#endregion 模拟配置类#region 配置服务使用线程安全的Lazy初始化
public class AppConfigService
{private static int _loadCounter = 0;  // 用于跟踪实际加载次数private static readonly Lazy<Configuration> _config = new Lazy<Configuration>(() => {Interlocked.Increment(ref _loadCounter);//记录实际初始化次数Console.WriteLine($">>> [线程 {Thread.CurrentThread.ManagedThreadId}] 开始加载配置...");Thread.Sleep(2000);  // 模拟数据库/IO延迟return new Configuration {Environment = "Production",MaxConnections = 100,LoadTime = DateTime.Now};}, LazyThreadSafetyMode.ExecutionAndPublication);public static Configuration Config => _config.Value; public static int LoadCount => _loadCounter;
}#endregion#region Usageclass Program
{static void Main(string[] args){Console.WriteLine("=== 配置加载测试(线程安全模式)===");Console.WriteLine($"主线程ID: {Thread.CurrentThread.ManagedThreadId}\n");// 创建10个并发请求线程Parallel.For(0, 10, i => {Thread.Sleep(new Random().Next(50));  // 随机延迟增加并发冲突概率Console.WriteLine($"[线程 {Thread.CurrentThread.ManagedThreadId}] 请求配置...");var config = AppConfigService.Config;Console.WriteLine($"[线程 {Thread.CurrentThread.ManagedThreadId}] 获取配置: {config}");});Console.WriteLine($"\n实际加载次数: {AppConfigService.LoadCount}");Console.WriteLine("测试完成。按任意键退出...");Console.ReadKey();}
}#endregion

输出:

=== 配置加载测试(线程安全模式)===
主线程ID: 1[线程 12] 请求配置...
>>> [线程 12] 开始加载配置...
[线程 6] 请求配置...
[线程 7] 请求配置...
[线程 8] 请求配置...
[线程 9] 请求配置...
[线程 4] 请求配置...
[线程 10] 请求配置...
[线程 1] 请求配置...
[线程 11] 请求配置...
[线程 13] 请求配置...
[线程 1] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 9] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 11] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 6] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 13] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 7] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 8] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 12] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 4] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947
[线程 10] 获取配置: [Production] MaxConnections=100, LoadTime=16:09:44.947实际加载次数: 1
测试完成。按任意键退出...

为何适用

  • 配置加载成本高(数据库查询)
  • 需确保所有线程获取同一实例
  • 需避免重复初始化导致资源浪费

2. 发布模式 (PublicationOnly)

场景:轻量级日志记录器

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;namespace PublicationOnlyLoggerDemo
{// 日志接口public interface ILogger{void Log(string message);}// 线程安全的文件日志记录器public class FileLogger : ILogger{private readonly string _filePath;// 静态锁确保多实例写入时的线程安全private static readonly object _fileLock = new object();// 记录已创建实例数量(用于演示)public static int InstanceCount = 0;// 记录实际写入次数(用于演示)public static readonly ConcurrentBag<string> AllLogs = new ConcurrentBag<string>();public FileLogger(string filePath){if (!File.Exists(filePath)){File.Create(filePath).Close();}_filePath = filePath;Interlocked.Increment(ref InstanceCount);lock (_fileLock){// 初始化日志文件File.WriteAllText(filePath, $"Log initialized at {DateTime.Now:HH:mm:ss.fff}\n");}}public void Log(string message){lock (_fileLock){File.AppendAllText(_filePath, $"{DateTime.Now:HH:mm:ss.fff} - {message}\n");}AllLogs.Add(message);}}// 日志工厂(使用PublicationOnly模式)public static class LoggerFactory{private static readonly Lazy<ILogger> _logger = new Lazy<ILogger>(() => new FileLogger("app.log"), LazyThreadSafetyMode.PublicationOnly);public static ILogger GetLogger() => _logger.Value;}class Program{static void Main(string[] args){Console.WriteLine("===开启并行日志记录测试===");// 并行日志记录测试Parallel.For(0, 10, i => {var logger = LoggerFactory.GetLogger();logger.Log($"Task {i} 开启");Thread.Sleep(50); // 模拟工作负载logger.Log($"Task {i} 完成");});// 显示统计结果Console.WriteLine("\n测试结果:");Console.WriteLine($"日志实例创建个数: {FileLogger.InstanceCount}");Console.WriteLine($"总计写入日志条目:{FileLogger.AllLogs.Count}");Console.WriteLine($"首次使用的日志实例:{FileLogger.AllLogs.First()}");Console.WriteLine($"最后使用的日志实例:{FileLogger.AllLogs.Last()}");Console.WriteLine("\n日志文件内容:");Console.WriteLine("-----------------");Console.WriteLine(File.ReadAllText("app.log"));Console.WriteLine("\n按任意键退出...");Console.ReadKey();}}
}

输出:


测试结果:
日志实例创建个数: 10
总计写入日志条目:20
首次使用的日志实例:Task 3 完成
最后使用的日志实例:Task 5 开启日志文件内容:
-----------------
Log initialized at 10:13:27.464
10:13:27.464 - Task 3 开启
10:13:27.518 - Task 0 完成
10:13:27.518 - Task 2 完成
10:13:27.518 - Task 4 完成
10:13:27.518 - Task 3 完成
10:13:27.518 - Task 5 完成
10:13:27.519 - Task 7 完成
10:13:27.519 - Task 8 完成
10:13:27.519 - Task 1 完成
10:13:27.519 - Task 6 完成
10:13:27.519 - Task 9 完成按任意键退出..."
===开启并行日志记录测试===测试结果:
日志实例创建个数: 10
总计写入日志条目:20
首次使用的日志实例:Task 3 完成
最后使用的日志实例:Task 5 开启日志文件内容:
-----------------
Log initialized at 10:13:27.464
10:13:27.464 - Task 3 开启
10:13:27.518 - Task 0 完成
10:13:27.518 - Task 2 完成
10:13:27.518 - Task 4 完成
10:13:27.518 - Task 3 完成
10:13:27.518 - Task 5 完成
10:13:27.519 - Task 7 完成
10:13:27.519 - Task 8 完成
10:13:27.519 - Task 1 完成
10:13:27.519 - Task 6 完成
10:13:27.519 - Task 9 完成按任意键退出...

为何适用

  • 日志初始化简单(创建文件句柄)
  • 可容忍短暂存在多个日志实例
  • 避免锁竞争提升性能

3. 结合依赖注入 (DI)

场景:解决循环依赖

遵循了依赖倒置原则,通过引入抽象层(Lazy代理)解耦了服务之间的直接依赖关系,解决循环依赖问题 。

using System;
using Microsoft.Extensions.DependencyInjection;public class Program
{static void Main(string[] args){// 设置依赖注入容器var services = new ServiceCollection();// 注册服务(注意顺序很重要)services.AddScoped<PaymentService>();services.AddScoped<OrderService>();// 使用Lazy打破循环依赖services.AddScoped(sp => new Lazy<OrderService>(() => sp.GetRequiredService<OrderService>()));using var serviceProvider = services.BuildServiceProvider();// 模拟请求范围using (var scope = serviceProvider.CreateScope()){var scopedProvider = scope.ServiceProvider;Console.WriteLine("解析OrderService...");var orderService = scopedProvider.GetRequiredService<OrderService>();Console.WriteLine("\n调用OrderService处理订单:");orderService.ProcessOrder(100.50m);}Console.WriteLine("\n按任意键退出...");Console.ReadKey();}
}public class OrderService
{private readonly PaymentService _paymentService;// 正常依赖PaymentServicepublic OrderService(PaymentService paymentService){Console.WriteLine(">>> OrderService 已创建");_paymentService = paymentService;}public void ProcessOrder(decimal amount){Console.WriteLine($"处理订单: ${amount}");_paymentService.ProcessPayment(amount);// 模拟其他操作Console.WriteLine("订单处理完成!");}public Order GetCurrentOrder() => new Order(DateTime.Now, 100.50m);
}public class PaymentService
{private readonly Lazy<OrderService> _lazyOrderService;// 通过Lazy间接依赖OrderServicepublic PaymentService(Lazy<OrderService> lazyOrderService){Console.WriteLine(">>> PaymentService 已创建");_lazyOrderService = lazyOrderService;}public void ProcessPayment(decimal amount){Console.WriteLine($"处理支付: ${amount}");// 按需访问OrderService(实际使用时才解析)Console.WriteLine("\n需要订单信息,访问Lazy.Value...");var currentOrder = _lazyOrderService.Value.GetCurrentOrder();Console.WriteLine($"获取到当前订单: {currentOrder}");}
}public record Order(DateTime CreatedTime, decimal Amount)
{public override string ToString() => $"[{CreatedTime:HH:mm:ss}] ${Amount}";
}

输出

解析OrderService...
>>> PaymentService 已创建
>>> OrderService 已创建调用OrderService处理订单:
处理订单: $100.50
处理支付: $100.50需要订单信息,访问Lazy.Value...
获取到当前订单: [10:44:31] $100.50按任意键退出...

说明:

遵循了依赖倒置原则,引入抽象层(Lazy代理),解耦了服务之间的直接依赖关系,解决循环依赖问题 。

  • 依赖倒置(DIP,Dependency Inversion Principle)设计

    • OrderService → 直接依赖 PaymentService
    • PaymentService → 依赖 Lazy<OrderService>(非直接依赖)
    • 关键点:将强依赖转换为弱依赖
    直接依赖
    依赖代理
    延迟解析
    OrderService
    PaymentService
    LazyProxy
  • 阶段说明

    • 构造阶段:只需要Lazy代理,不触发实际解析

      DI容器OrderServicePaymentServiceLazy包装器尝试创建需要依赖请求依赖返回未初始化代理返回实例创建成功DI容器OrderServicePaymentServiceLazy包装器
      • PaymentService 只需要一个"承诺"(Lazy代理),不需要实际 OrderService 实例
      • 避免初始化死锁
    • 执行阶段:依赖树已建立,安全访问

      AppOrderServicePaymentServiceLazy包装器DI容器调用方法传递调用访问.Value请求真实实例返回已存在的OrderService返回真实实例完成操作AppOrderServicePaymentServiceLazy包装器DI容器
      • 首次访问 .Value 触发实际解析
      • 此时 OrderService 已完全初始化
      • 后续访问使用缓存实例

为何适用

  • 解决紧耦合服务的循环引用问题
  • 延迟初始化高开销服务(如数据库连接)
  • 动态插件加载(Lazy<IPlugin> 按需激活)

使用场景总结

场景技术选型理由
全局配置/缓存线程安全模式多线程共享 + 单次初始化
轻量级工具类(如日志)发布模式允许冗余初始化 + 避免锁性能损耗
UI组件/单线程模块非线程安全模式明确线程上下文 + 零开销
DI容器中的复杂服务`Lazy<T>`注入打破循环依赖 + 按需加载
网络请求/文件加载`Lazy<Task<T>>` 或 `AsyncLazy<T>`非阻塞初始化 + 结果缓存

6. 注意事项与最佳实践

注意点建议做法
构造函数中不要访问 `.Value`会导致死循环或异常
避免在委托中抛出异常使用 try-catch 包裹初始化逻辑,或设置异常处理策略
使用 `IsValueCreated` 检查状态可用于调试或日志输出

7. 总结

  • 优势

    平衡性能与资源,提供线程安全的按需初始化。

  • 注意

    1. 优先选择默认线程安全模式。
    2. 避免在频繁调用的方法中滥用。 (存在锁竞争/异常放大
    3. 谨慎处理初始化异常。

LazyInitializer

官方文档:LazyInitializer.EnsureInitialized 方法 (System.Threading) | Microsoft Learn

源码:LazyInitializer.cs

1. 概念

  • 基本信息
    • 命名空间System.Threading
    • 程序集System.Threading.dll
    • 继承关系ObjectLazyInitializer
  • 特性
    特性说明
    零分配开销避免创建专用延迟初始化实例,比 `Lazy<T>` 更轻量(无额外对象分配)
    引用初始化通过引用传递确保初始化状态一致性
    线程安全内部通过锁或原子操作保证线程安全,支持多线程并发调用
    静态方法直接操作字段,无需创建包装器
    异常处理初始化函数抛出异常时,后续访问会重试(与 `Lazy<T>` 的缓存异常不同)
    轻量级替代方案相比 `Lazy<T>` ,无需额外包装对象,直接操作目标字段。
  • 示例
    ExpensiveData _data = null;
    bool _dataInitialized = false;
    object _dataLock = new object();// 使用示例
    ExpensiveData dataToUse = LazyInitializer.EnsureInitialized(ref _data,ref _dataInitialized,ref _dataLock);
    

2. 方法重载详解

  • 🔧 方法列表

    EnsureInitialized\<T>(T)在目标引用或值类型尚未初始化的情况下,使用其类型的无参数构造函数初始化目标引用类型。
    EnsureInitialized\<T>(T, Boolean, Object)在目标引用或值类型尚未初始化的情况下,使用其无参数构造函数对其进行初始化。
    EnsureInitialized\<T>(T, Boolean, Object, Func\<T>)在目标引用或值类型尚未初始化的情况下,使用指定函数初始化目标引用或值类型。
    EnsureInitialized\<T>(T, Func\<T>)在目标引用类型尚未初始化的情况下,使用指定函数初始化目标引用类型。
    EnsureInitialized\<T>(T, Object, Func\<T>)在目标引用类型尚未初始化的情况下,使用指定函数初始化目标引用类型。
  • 重载 1:默认构造函数

    public static T EnsureInitialized<T> (ref T? target) where T : class;
    • 适用场景:类型有无参构造函数
    • 线程安全:低竞争环境下安全(可能多次构造但最终保留一个实例,类似与Lazy<T>的PublicationOnly模式)
    • 返回: 已初始化的对象。
    • 示例
      private ExpensiveResource _resource;
      public ExpensiveResource Resource => LazyInitializer.EnsureInitialized(ref _resource);
      
  • 重载 2:自定义初始化函数

    public static T EnsureInitialized<T> (ref T? target, Func<T> valueFactory) where T : class;
    • 适用场景:需参数化构造或复杂初始化逻辑
    • 线程安全:低竞争环境下安全(可能多次构造但最终保留一个实例)
    • 返回: 已初始化的对象。
    • 示例
      private DatabaseConnection _db;
      public DatabaseConnection Db => LazyInitializer.EnsureInitialized(ref _db, () => new DatabaseConnection(_config));
      
  • 重载 3:完全线程安全控制

    public static T EnsureInitialized<T> (ref T target, ref bool initialized, ref object? syncLock, Func<T> valueFactory);
    
    • 适用场景:高并发环境要求严格单次初始化
    • 参数说明
      1. ref T target:需确保初始化的目标对象。 如果是 null,则将其视为未初始化;否则,将其视为已初始化。
      2. ref bool initialized:跟踪初始化状态。如果 initialized 指定为 true,则不会进一步初始化。
      3. ref object syncLock:同步锁对象(可传入 null,方法内部初始化)
      4. Func<T> valueFactory:创建对象的工厂方法,未初始化时调用此方法生成新实例,支持自定义逻辑(如构造函数、依赖注入等)。
    • 示例
      private Logger _logger;
      private bool _loggerInitialized;
      private object _loggerLock = new object();public Logger Logger => LazyInitializer.EnsureInitialized(ref _logger, ref _loggerInitialized, ref _loggerLock, () => new Logger("app.log"));
      

3. 与 Lazy 的对比

特性LazyInitializer.EnsureInitialized()Lazy\<T>
内存开销无额外对象分配(直接操作字段)需分配 `Lazy<T>` 包装器实例
异常缓存不缓存异常(每次失败后重试)缓存异常(首次异常后永远抛出)
适用类型仅引用类型支持值类型和引用类型
初始化状态跟踪需手动管理内置状态管理

4. 最佳实践

  1. 首选场景
    • 性能敏感且需最小化内存开销时
    • 直接初始化现有字段(非新属性)
  2. 线程安全建议
    • 低竞争环境 → 使用重载 1 或 2
    • 高并发场景 → 使用重载 3(严格单次初始化)
  3. 锁对象管理
    • 传入 null 让方法初始化锁对象:

      object _lock = null; // 方法内部会替换为 new object()
      
    • 若需复用同一锁,提前初始化锁对象

  4. 避免值类型:不支持值类型(编译错误),需改用 Lazy<T>

5. 总结

通过引用传递和锁对象机制,LazyInitializer 提供了比 Lazy<T> 更轻量的延迟初始化方案,适用于需要精细控制初始化过程的场景。

  • 优势:轻量高效、直接操作字段、灵活控制线程安全。
  • 适用:引用类型的延迟初始化,性能敏感场景。
  • 注意
    • 高并发环境须使用重载 3
    • 需要异常重试逻辑时优先选择(与 Lazy<T> 异常缓存行为不同)
    • 避免用于值类型

选择建议

  • 如果需要快速实现线程安全的延迟初始化且对性能要求不是极致,可优先选择Lazy<T>
  • 如果在性能敏感的场景下,且初始化逻辑简单,可选择LazyInitializer.EnsureInitialized

总结

Lazy<T>LazyInitializer.EnsureInitialized可以实现延迟初始化,按需加载资源,提升启动性能并节省内存。

Lazy<T>提供了封装良好的延迟初始化机制,支持复杂的初始化逻辑和多种线程安全模式,适用于需要延迟加载的场景。

LazyInitializer.EnsureInitialized 则更加轻量级,直接操作字段,适用于性能敏感且需要最小化内存开销的场景。

在实际应用中,需要根据具体需求选择合适的方式。

  1. 需要线程安全的场景,Lazy<T>的默认模式(ExecutionAndPublication)是首选;
  2. 而对于性能敏感且初始化逻辑简单的场景,LazyInitializer.EnsureInitialized 的重载提供了更高效的解决方案。
  3. 同时,开发者还需要注意异常处理、线程安全模式的选择以及避免滥用延迟初始化导致的性能问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/93490.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93490.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LLIE专题】LLIE低照度图像结构先验提取方法

Zero-Shot Day-Night Domain Adaptation with a Physics Prior&#xff08;ICCV,2021&#xff09;专题介绍一、研究背景二、方法1. 物理反射模型与颜色不变特征的推导&#xff08;原理推导、物理依据&#xff09;2. 颜色不变特征的计算&#xff08;特征计算公式整个过程&#x…

Font Awesome Kit 使用详解

在现代网页设计中&#xff0c;图标是提升用户体验的关键元素。而 Font Awesome 作为最受欢迎的图标库&#xff0c;其最新版本 Font Awesome 7 通过 Kit 功能提供了更便捷高效的集成方式。本文将带你全面了解如何使用 Font Awesome Kit&#xff0c;让你的网站图标管理变得轻松高…

第七十八章:AI的“智能美食家”:输出图像风格偏移的定位方法——从“滤镜病”到“大师风范”!

AI图像风格偏移前言&#xff1a;AI的“火眼金睛”——输出图像风格偏移的定位方法&#xff01;第一章&#xff1a;痛点直击——“画风跑偏”&#xff1f;AI生成艺术的“审美危机”&#xff01;第二章&#xff1a;探秘“画风密码”&#xff1a;什么是风格偏移&#xff1f;它藏在…

Android原生(Kotlin)与Flutter混合开发 - 设备控制与状态同步解决方案

Kotlin 原生实现 (Android) 1.1 AndroidManifest.xml <manifest xmlns:android"http://schemas.android.com/apk/res/android"package"com.afloia.smartconnect"><applicationandroid:name".MainApplication"android:label"Smart …

已开源:Highcharts.NET,Highcharts Android,与Highcharts iOS集成

近期了解到&#xff0c;Highcharts官方宣布将Highcharts.NET&#xff0c;Highcharts Android&#xff0c;与Highcharts iOS集成转换为开源。对于Highcharts提供世界一流的数据可视化工具&#xff0c;一直致力于将资源集中在可以为您提供最大价值的地方。官方提到&#xff1a;这…

KingbaseES:一体化架构与多层防护,支撑业务的持续稳定运行与扩展

声明&#xff1a;文章为本人真实测评博客&#xff0c;非广告 目录 引言 一、什么是KingbaseES&#xff1f; 二、KingbaseES核心特性 1. 一键迁移&#xff0c;极速性能&#xff0c;安全无忧​ 2. 性能强劲&#xff0c;扩展性强&#xff0c;助力企业应对大规模并发挑战​ …

scikit-learn/sklearn学习|广义线性回归 Logistic regression的三种成本函数

【1】引言 前序学习进程中&#xff0c;已经对线性回归和岭回归做了初步解读。 实际上&#xff0c; Logistic regression是一种广义的线性模型&#xff0c;在对线性分类的进一步学习前&#xff0c;有必要了解 Logistic regression。 【2】Logistic regression的3种成本函数 …

Tiptap(基于 Prosemirror)vs TinyMCE:哪个更适合你的技术栈?

在这之前&#xff0c;先来介绍一下 ProseMirror&#xff1a; 1. ProseMirror 是底层内核 定位&#xff1a;一个强大的 富文本编辑框架/引擎&#xff0c;不是一个成品编辑器。 作者&#xff1a;Marijn Haverbeke&#xff08;CodeMirror 作者&#xff09;。 核心思想&#xff1…

多墨智能-AI一键生成工作文档/流程图/思维导图

本文转载自&#xff1a;多墨智能-AI一键生成工作文档/流程图/思维导图 - Hello123工具导航 ** 一、AI 文档与视觉化创作助手 多墨智能是一款基于人工智能的在线工具&#xff0c;支持一键生成专业文档、流程图与思维导图&#xff0c;通过关键词输入快速完成内容创作&#xff0…

Kafka_Broker_副本基本信息

Kafka副本作用&#xff1a;提高数据可靠性 Kafka默认副本1个&#xff0c;生产环境一般配置为2个&#xff0c;保证数据可靠性&#xff0c;太多副本会增加磁盘存储空间&#xff0c;增加网络上数据传输&#xff0c;降低效率 Kafka中副本分为&#xff1a;Leader和Follower&#xff…

FreeRTOS 中的守护任务(Daemon Task)

在 FreeRTOS 中&#xff0c;守护任务&#xff08;Daemon Task&#xff09;是一个特殊的系统任务&#xff0c;主要用于管理软件定时器和其他后台操作。以下是关于 FreeRTOS 守护任务的详细信息&#xff1a; 守护任务的作用软件定时器管理&#xff1a; 当启用 configUSE_TIMERS 时…

博士招生 | 麻省理工学院 招收化学+人工智能方向 博士/博士后

内容源自“图灵学术博研社”gongzhonghao学校简介麻省理工学院&#xff08;MIT&#xff09;QS世界排名第1&#xff0c;是全球科技研究领域的顶尖学府。自成立以来&#xff0c;MIT以其卓越的科研和教育质量赢得了世界的尊敬。学校在科学、工程、经济和管理等多个领域具有深远的影…

云计算-OpenStack 实战运维:从组件配置到故障排查(含 RAID、模板、存储管理,网络、存储、镜像、容器等)

介绍 在云计算技术快速发展的背景下,OpenStack 作为开源的云计算管理平台,凭借其灵活性、可扩展性和强大的组件生态,成为构建私有云、公有云和混合云的重要选择。无论是云主机的创建与管理、存储方案的配置(如 RAID 阵列、Swift 对象存储、Cinder 块存储),还是网络编排、…

idea代码bug检测插件

代码检测工具&#xff08;插件&#xff09;推荐&#xff1a;Alibaba Java Coding Guidelines、CheckStyle、PMD、FindBugs、SonarLint。可以在idea中安装插件 让你在关注代码质量的同时&#xff0c;减少 code review 的工作量&#xff0c;提高 code review 的效率&#xff0c;…

Java String为什么要设计成不可变的?

大家好&#xff0c;我是锋哥。今天分享关于【Java String为什么要设计成不可变的?】面试题。希望对大家有帮助&#xff1b; Java String为什么要设计成不可变的? 超硬核AI学习资料&#xff0c;现在永久免费了&#xff01; Java中的String类被设计为不可变&#xff08;immut…

集成电路学习:什么是ORB方向性FAST和旋转BRIEF

ORB:方向性FAST和旋转BRIEF ORB(Oriented FAST and Rotated BRIEF)是一种在计算机视觉领域广泛应用的特征描述算法,它结合了FAST角点检测算法和BRIEF描述子算法的优点,以实现高效且具有旋转不变性的特征提取和匹配。以下是关于ORB算法的详细解析: 一、ORB算法概述 …

【langgraph基础入门】

1. LangGraph图结构概念说明在以图构建的框架中&#xff0c;任何可执行的功能都可以作为对话、代理或程序的启动点。这个启动点可以是大模型的 API 接口、基于大模型构建的 AI Agent&#xff0c;通过 LangChain 或其他技术建立的线性序列等等&#xff0c;即下图中的 “Start” …

[逆向知识] AST抽象语法树:混淆与反混淆的逻辑互换(一)

博客配套代码发布于github&#xff1a;半自动化cookie更新&#xff08;欢迎顺手Star一下⭐&#xff09; 相关逆向知识&#xff1a; [逆向知识] AST抽象语法树&#xff1a;混淆与反混淆的逻辑互换&#xff08;二&#xff09;-CSDN博客 相关爬虫专栏&#xff1a;JS逆向爬虫实战…

网络安全合规6--服务器安全检测和防御技术

一、服务器安全风险主要威胁&#xff1a;不必要的服务暴露&#xff08;如仅需HTTP却开放多余端口&#xff09;。外网扫描&#xff08;IP/端口扫描&#xff09;、DDoS攻击。系统漏洞攻击&#xff08;操作系统、软件版本已知漏洞&#xff09;。Web攻击&#xff08;SQL注入、XSS、…

Mutually aided uncertainty

cycle loss calculation in order to regularize the two aux-decoders 辅助信息 作者未提供代码