亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#使用Lazy實現(xiàn)延遲加載的方法示例

 更新時間:2024年06月13日 10:44:35   作者:白話Learning  
在C#中,Lazy< T> 類是一個非常有用的工具,它可以用于延遲加載值,在本文中,我們將詳細介紹 Lazy< T> 的實現(xiàn)機制和用法,并提供一些示例來展示它的優(yōu)勢,文中通過代碼示例講解的非常詳細,需要的朋友可以參考下

前言

在C#中,Lazy< T> 類是一個非常有用的工具,它可以用于延遲加載值,尤其是在創(chuàng)建對象時可能很昂貴,或者你想要延遲初始化直到真正需要該值的情況下。在本文中,我們將詳細介紹 Lazy< T> 的實現(xiàn)機制和用法,并提供一些示例來展示它的優(yōu)勢。

1、Lazy 的工作原理

Lazy< T> 類是.NET框架中的一個并發(fā)類,它允許你延遲初始化一個對象,直到這個對象被第一次使用時才進行。這意味著,如果多個線程需要訪問同一個延遲初始化的對象,Lazy< T> 能夠保證只有一個線程會執(zhí)行初始化代碼,從而避免不必要的資源消耗。

Lazy< T> 采用懶漢式初始化模式,在.NET Framework 4.0及之前的版本中,它是線程安全的,采用內(nèi)部互斥鎖(Mutex)來確保線程安全。但在.NET 4.0之后,Lazy< T> 采用了新的LazyInitializationMode.None模式,允許非線程安全且更高效的初始化,這時需要開發(fā)者自己確保初始化的線程安全。

2、創(chuàng)建 Lazy 實例

要創(chuàng)建一個 Lazy< T> 實例,你可以使用以下構(gòu)造函數(shù):

Lazy<T>() : this(LazyThreadSafetyMode.ExecutionAndPublication)
Lazy<T>(Func<T> valueFactory) : this(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication)
Lazy<T>(LazyThreadSafetyMode mode)
Lazy<T>(Func<T> valueFactory, LazyThreadSafetyMode mode)

LazyThreadSafetyMode 是一個枚舉,用于指定初始化時的線程安全模式。有四種模式:

  • LazyThreadSafetyMode.None:允許非線程安全初始化。
  • LazyThreadSafetyMode.ExecutionAndPublication:執(zhí)行初始化時是線程安全的,且Publish方法也是線程安全的。
  • LazyThreadSafetyMode.PublicationOnly:僅Publish方法是線程安全的。
  • LazyThreadSafetyMode.UnprotectedPublication:既不是執(zhí)行時也不是發(fā)布時線程安全。

3、 使用 Lazy

一旦你創(chuàng)建了一個 Lazy< T> 實例,你可以通過其 Value 屬性來獲取其內(nèi)部值的引用,該屬性是只讀的,并會在第一次訪問時觸發(fā)值的初始化。

4、示例

下面我們通過一個示例來演示如何使用 Lazy 進行延遲加載。

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

class Program
{
    static void Main(string[] args)
    {
        // 使用 Lazy<T> 創(chuàng)建一個延遲加載的對象
        Lazy<ExpensiveObject> lazyExpensiveObject = new Lazy<ExpensiveObject>(() => new ExpensiveObject(), LazyThreadSafetyMode.ExecutionAndPublication);

        // 獲取對象值,這將觸發(fā)延遲加載
        ExpensiveObject expensiveObject = lazyExpensiveObject.Value;

        // 使用 expensiveObject 做些事情
        Console.WriteLine(expensiveObject.SomeProperty);

        Console.ReadKey();
    }
}

class ExpensiveObject
{
    public ExpensiveObject()
    {
        // 模擬一個初始化代價很昂貴的操作
        Console.WriteLine("Expensive object initialized.");
    }

    public string SomeProperty { get; set; }
}

在這個示例中,我們創(chuàng)建了一個 ExpensiveObject 的 Lazy 實例。這個 ExpensiveObject 的構(gòu)造函數(shù)是一個耗時的操作。當(dāng)我們第一次訪問 lazyExpensiveObject.Value 時,構(gòu)造函數(shù)會被調(diào)用,并且 ExpensiveObject 實例會被創(chuàng)建。注意,之后對這個屬性的所有訪問都會直接返回已經(jīng)創(chuàng)建的實例,而不會再次調(diào)用構(gòu)造函數(shù)。

注意事項

  1. 如果你需要在多個線程中共享延遲加載的對象,請確保你正確同步對這個對象的訪問。
  2. 如果你的初始化操作是線程安全的,你可以使用 LazyThreadSafetyMode.ExecutionAndPublication,這樣可以保證初始化過程和發(fā)布過程都是線程安全的。
  3. 如果你的初始化操作不依賴于外部狀態(tài),并且你確信它可以在多個線程中安全地并行執(zhí)行,你可以使用 LazyThreadSafetyMode.None,這將避免線程鎖定,并可能提高性能。

5、Lazy< T> 實現(xiàn)延遲加載

Lazy< T> 利用了 C# 的屬性器和反射機制來實現(xiàn)延遲加載。當(dāng)訪問 Lazy< T> 的 Value 屬性時,如果內(nèi)部值尚未初始化,則初始化它。這個過程稱為“lazy initialization”。Lazy< T> 提供了幾種不同的線程安全模式,以適應(yīng)不同的場景。

實現(xiàn)方式

下面是使用 Lazy 進行延遲加載資源的基本步驟:

  • 創(chuàng)建一個 Lazy 實例,并通過提供一個函數(shù)來指定要延遲加載的資源。
  • 在需要的時候,通過訪問 Lazy 的 Value 屬性來觸發(fā)資源的加載。

示例:延遲加載圖片

假設(shè)我們有以下一個類,它使用 Lazy 來延遲加載圖片:

using System;
using System.Drawing;
using System.Threading.Tasks;

public class ImageLoader
{
    private Lazy<Bitmap> _lazyImage = new Lazy<Bitmap>(() => LoadImageAsync("path/to/image.jpg"), LazyThreadSafetyMode.ExecutionAndPublication);

    public Bitmap GetImage()
    {
        return _lazyImage.Value;
    }

    private async Task<Bitmap> LoadImageAsync(string imagePath)
    {
        using (var stream = new FileStream(imagePath, FileMode.Open))
        {
            return (Bitmap)Image.FromStream(stream);
        }
    }
}

在這個例子中,ImageLoader 類有一個 Lazy 實例,它通過異步方法 LoadImageAsync 加載圖片。當(dāng)調(diào)用 GetImage 方法時,Lazy 會觸發(fā) LoadImageAsync 的執(zhí)行,并返回圖片。

示例:延遲加載視頻

視頻加載通常涉及到更復(fù)雜的操作,下面是一個簡化的例子:

using System;
using System.IO;
using System.Threading.Tasks;

public class VideoLoader
{
    private Lazy<FileStream> _lazyVideoStream = new Lazy<FileStream>(() => LoadVideoAsync("path/to/video.mp4"), LazyThreadSafetyMode.ExecutionAndPublication);

    public FileStream GetVideoStream()
    {
        return _lazyVideoStream.Value;
    }

    private async Task<FileStream> LoadVideoAsync(string videoPath)
    {
        return new FileStream(videoPath, FileMode.Open);
    }
}

在這個例子中,VideoLoader 類使用 Lazy 來延遲加載視頻文件流。當(dāng) GetVideoStream 被調(diào)用時,視頻文件流會被創(chuàng)建并返回。

示例:延遲加載音頻

音頻文件的加載可以類似于視頻文件的加載:

using System;
using System.IO;
using System.Threading.Tasks;

public class AudioLoader
{
    private Lazy<FileStream> _lazyAudioStream = new Lazy<FileStream>(() => LoadAudioAsync("path/to/audio.wav"), LazyThreadSafetyMode.ExecutionAndPublication);

    public FileStream GetAudioStream()
    {
        return _lazyAudioStream.Value;
    }

    private async Task<FileStream> LoadAudioAsync(string audioPath)
    {
        return new FileStream(audioPath, FileMode.Open);
    }
}

在這個例子中,AudioLoader 類使用 Lazy 來延遲加載音頻文件流。當(dāng) GetAudioStream 被調(diào)用時,音頻文件流會被創(chuàng)建并返回。

6、如何在多線程環(huán)境中測試 Lazy<T> 的線程安全性?

在多線程環(huán)境中測試 Lazy< T> 的線程安全性通常涉及到模擬 concurrent access(并發(fā)訪問)來確保 Lazy< T> 在不同線程之間正確地處理初始化和訪問。這里有幾種方法可以用來測試 Lazy< T> 的線程安全性:

  1. 使用 Lazy< T> 的同步模式: 在 Lazy 的構(gòu)造函數(shù)中指定 LazyThreadSafetyMode.ExecutionAndPublication 或 LazyThreadSafetyMode.PublicationOnly,這樣 Lazy< T> 會確保在多個線程中的執(zhí)行和發(fā)布都是線程安全的。
  2. 手動同步: 如果你使用的是 LazyThreadSafetyMode.None,你需要手動同步對 Lazy< T> 屬性的訪問。這可以通過 lock 語句或 Monitor 類來實現(xiàn)。
  3. 使用 Task 和 Parallel 類: 使用 Task 并行庫來創(chuàng)建多個任務(wù),每個任務(wù)訪問 Lazy 的 Value 屬性。確保在所有任務(wù)都完成時,Lazy< T> 的初始化只執(zhí)行一次。
  4. 使用 Mutex 或 Semaphore: 使用 Mutex 或 Semaphore 來控制對 Lazy< T> 初始化代碼的訪問,確保初始化是獨占進行的。
  5. 單元測試: 編寫單元測試來模擬并發(fā)訪問??梢允褂脺y試框架(如 NUnit 或 xUnit)來創(chuàng)建多個測試線程,并確保它們正確地訪問 Lazy< T>。
  6. 代碼分析工具: 使用像 NDepend 或 SonarQube 這樣的代碼分析工具來檢測可能的線程安全問題。
    下面是一個簡單的示例,展示了如何在單元測試中使用 Lazy< T> 和 Task 來測試線程安全性:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public class LazyTestClass
{
    private Lazy<List<int>> _lazyList = new Lazy<List<int>>(() => new List<int>(), LazyThreadSafetyMode.ExecutionAndPublication);

    public List<int> GetList()
    {
        return _lazyList.Value;
    }
}

public class Program
{
    public static void Main()
    {
        LazyTestClass testClass = new LazyTestClass();

        // 創(chuàng)建多個任務(wù)來并發(fā)訪問 Lazy<T>
        var tasks = Enumerable.Range(1, 10).Select(i => Task.Run(() => testClass.GetList()));

        // 等待所有任務(wù)完成
        Task.WaitAll(tasks.ToArray());
    }
}

// 單元測試
public class LazyTestClassTests
{
    [Fact]
    public void TestLazyThreadSafety()
    {
        LazyTestClass testClass = new LazyTestClass();

        // 創(chuàng)建多個測試線程
        var tasks = Enumerable.Range(1, 10).Select(i => Task.Run(() => testClass.GetList()));

        // 等待所有任務(wù)完成
        Task.WaitAll(tasks.ToArray());

        // 斷言列表的實例只有一個
        Assert.Single(tasks.Select(t => t.Result));
    }
}

在這個示例中,我們創(chuàng)建了一個 LazyTestClass,它有一個 Lazy<List> 成員。我們在主函數(shù)中創(chuàng)建了多個 Task 來并發(fā)地訪問 GetList 方法,該方法返回 Lazy<List> 的值。在單元測試中,我們使用 Fact 屬性來標(biāo)記一個測試方法,并使用 Assert.Single 來斷言只有一個 List 實例被創(chuàng)建。

7、Lazy 加載在性能和用戶體驗方面的作用

Lazy 加載技術(shù)可以顯著提高程序的性能和用戶體驗。以下是它在不同方面的一些潛在作用:

  • 性能提升:通過延遲加載昂貴的資源,程序可以在不需要這些資源時避免不必要的開銷。這意味著資源只有在真正需要時才會被加載,從而減少內(nèi)存和CPU的使用。
  • 響應(yīng)性增強:在用戶界面(UI)中使用 Lazy 加載可以避免在初始加載時延遲UI的響應(yīng)。這對于創(chuàng)建快速啟動的應(yīng)用程序至關(guān)重要。
  • 資源優(yōu)化:對于大型資源,如圖片、視頻和音頻文件,Lazy 加載確保只有在用戶請求時才加載它們,這樣可以減少應(yīng)用程序的整體大小和加載時間。
  • 多線程支持:Lazy 加載在多線程環(huán)境中自動同步,這意味著不必擔(dān)心在多個線程中共享和初始化資源的問題。

8、安全性和效率考慮

盡管 Lazy 加載提供了許多好處,但在使用時也需要考慮安全和效率:

  • 線程安全:Lazy 加載默認是線程安全的,但在自定義 Lazy 實現(xiàn)或使用 LazyThreadSafetyMode.None 時,需要確保線程安全。
  • 資源泄漏:如果異步加載的資源沒有正確管理(例如,沒有釋放或關(guān)閉流),可能會導(dǎo)致資源泄漏。
  • 性能開銷:即使是 Lazy 加載,如果初始化過程很昂貴,或者在短時間內(nèi)多次調(diào)用 Value 屬性,這可能會導(dǎo)致性能問題。
  • 過度依賴:過度使用 Lazy 加載可能會導(dǎo)致代碼難以理解和維護,特別是當(dāng)依賴關(guān)系變得復(fù)雜時。

總結(jié)

Lazy< T> 是C#中一個非常有用的并發(fā)特性,它允許開發(fā)者延遲初始化對象,直到這些對象真正被需要。通過正確使用 Lazy< T>,你可以優(yōu)化應(yīng)用程序的性能,減少資源消耗,并提高應(yīng)用程序的響應(yīng)性。

在使用 Lazy< T> 時,你需要仔細考慮線程安全問題,并選擇合適的 LazyThreadSafetyMode。此外,你還需要確保在多個線程中共享延遲加載的對象時,你的初始化代碼和發(fā)布代碼都是線程安全的。

以上就是C#使用Lazy實現(xiàn)延遲加載的方法示例的詳細內(nèi)容,更多關(guān)于C# Lazy延遲加載的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#的Excel導(dǎo)入、導(dǎo)出

    C#的Excel導(dǎo)入、導(dǎo)出

    這篇文章主要為大家詳細介紹了C#的Excel導(dǎo)入、導(dǎo)出的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • 詳解C#中==、Equals、ReferenceEquals的區(qū)別

    詳解C#中==、Equals、ReferenceEquals的區(qū)別

    C#中Equals , == , ReferenceEquals都可以用于判斷兩個對象的個體是不是相等,本篇文章詳解C#中Equals , == , ReferenceEquals都可以用于判斷兩個對象的個體是不是相等,有興趣的可以了解一下。
    2016-12-12
  • C#實現(xiàn)寫系統(tǒng)日志的方法

    C#實現(xiàn)寫系統(tǒng)日志的方法

    這篇文章主要介紹了C#實現(xiàn)寫系統(tǒng)日志的方法,涉及C#針對系統(tǒng)日志的創(chuàng)建、寫入及刪除等技巧,非常具有實用價值,需要的朋友可以參考下
    2015-08-08
  • C#適配器模式的使用

    C#適配器模式的使用

    本文主要介紹了C#適配器模式的使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • C#檢查字符串是否是合法URL地址的方法

    C#檢查字符串是否是合法URL地址的方法

    這篇文章主要介紹了C#檢查字符串是否是合法URL地址的方法,涉及C#字符串判斷的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • C#解析json字符串總是多出雙引號的原因分析及解決辦法

    C#解析json字符串總是多出雙引號的原因分析及解決辦法

    json好久沒用了,今天在用到j(luò)son的時候,發(fā)現(xiàn)對字符串做解析的時候總是多出雙引號,下面給大家介紹C#解析json字符串總是多出雙引號的原因分析及解決辦法,需要的朋友參考下吧
    2016-03-03
  • C#串口通信工具類的封裝

    C#串口通信工具類的封裝

    這篇文章主要為大家詳細介紹了C#串口通信工具類封裝,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • winform 實現(xiàn)控制輸入法

    winform 實現(xiàn)控制輸入法

    在工作中遇到這樣一個問題,在系統(tǒng)使用過程中,輸入法會變灰導(dǎo)致無法使用輸入法輸入文字,就好像輸入法被禁用了沒有啟用似的。對此,在這里做個備錄
    2015-08-08
  • C#中調(diào)用命令行cmd開啟wifi熱點的實例代碼

    C#中調(diào)用命令行cmd開啟wifi熱點的實例代碼

    最近想在win7上開啟wifi熱點,于是就弄出下面這個小東西,里面涉及如何在控制臺上輸入命令,分享一下。首先在VS中創(chuàng)建一個window窗口,然后創(chuàng)建兩個四個button,兩個輸入框
    2013-04-04
  • C#實現(xiàn)全局快捷鍵功能

    C#實現(xiàn)全局快捷鍵功能

    這篇文章介紹了C#實現(xiàn)全局快捷鍵功能的方法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06

最新評論