.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
英文地址,請注明出處:http://en.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 輔助信息 作者未提供代碼