【C#進階】多執行緒和非同步程式設計_2024-06-22

StarYou發表於2024-06-22

關於多執行緒和非同步程式設計簡單來說,就是多執行緒並行執行任務提速,非同步程式設計等待不浪費資源,併發集合確保資料訪問安全,三者合力提升程式效率與反應能力。

1. 理解執行緒

想象一下,你在廚房做飯,同時需要洗菜、切菜、炒菜。如果你一個人來做,就需要在這些任務之間來回切換,這很慢。但如果請幾個朋友幫忙,每人負責一項任務,大家同時工作,效率就高多了。這裡的“朋友”就像是計算機中的“執行緒”。

執行緒就是計算機程式中執行任務的最小單位。一個程式預設啟動時只有一個主執行緒,但可以透過建立額外的執行緒來同時執行多個任務,這就是多執行緒

示例程式碼:

using System;
using System.Threading;

class MultiThreadingDemo
{
    static void Main()
    {
        // 這是主執行緒
        Console.WriteLine("主執行緒開始");
        
        // 建立並啟動一個新的執行緒
        Thread thread = new Thread(DoWork);
        thread.Start();
        
        Console.WriteLine("主執行緒繼續做其他事情");
        
        // 等待新執行緒完成(非必須,這裡為了演示)
        thread.Join();
        
        Console.WriteLine("所有任務完成,主執行緒結束");
    }
    
    static void DoWork()
    {
        Console.WriteLine("新執行緒開始執行任務");
        Thread.Sleep(2000); // 模擬耗時操作
        Console.WriteLine("新執行緒任務完成");
    }
}

註釋說明:這段程式碼中,Main方法所在的執行緒是主執行緒,它建立了一個新執行緒DoWork去執行一個耗時任務。Thread.Sleep(2000)模擬了這個耗時操作,讓新執行緒暫停2秒,期間主執行緒可以繼續執行其他任務。

2. Task和非同步程式設計模型(async和await)

有時候,我們不希望直接管理執行緒,而是希望程式自動為我們處理併發問題。這時候,就可以使用.NET提供的Taskasync/await關鍵字。

想象你在等待外賣,你可以選擇一直站在門口等(阻塞),也可以繼續做其他事,聽到門鈴響再去拿(非同步)。async/await就是讓你的程式在等待某些耗時操作(如網路請求)時,可以去做別的事,不浪費時間。

示例程式碼:

using System;
using System.Threading.Tasks;

class AsyncDemo
{
    static async Task Main()
    {
        Console.WriteLine("開始下載檔案");
        
        // 非同步下載檔案,不會阻塞主執行緒
        await DownloadFileAsync();
        
        Console.WriteLine("檔案下載完成");
    }
    
    static async Task DownloadFileAsync()
    {
        // 模擬檔案下載耗時操作
        await Task.Delay(2000);
        Console.WriteLine("檔案下載中...");
    }
}

註釋說明DownloadFileAsync方法模擬了檔案下載,使用Task.Delay(2000)模擬耗時操作。await關鍵字讓呼叫它的方法(這裡是Main方法)在等待時可以“放手”,去做其他事情,直到DownloadFileAsync完成才繼續往下執行。

3. 併發集合和執行緒安全

當你在多執行緒環境下訪問和修改共享資料時,可能會遇到資料不一致的問題,這叫做“競態條件”。為了解決這個問題,.NET提供了執行緒安全的集合,比如ConcurrentDictionary

想象你和朋友同時編輯一份購物清單,如果不小心同時新增了同樣的物品,就會出錯。執行緒安全的集合就像每個人都有自己的筆,在寫之前先確認沒人同時寫,保證清單的正確性。

示例程式碼:

using System.Collections.Concurrent;
using System.Threading.Tasks;

class ThreadSafeCollectionsDemo
{
    static ConcurrentDictionary<string, int> shoppingList = new ConcurrentDictionary<string, int>();

    static async Task AddItemAsync(string item)
    {
        // 嘗試新增或更新數量,執行緒安全
        shoppingList.AddOrUpdate(item, 1, (key, oldValue) => oldValue + 1);
        await Task.Yield(); // 模擬一點點耗時,讓併發效果更明顯
    }

    static async Task Main()
    {
        var tasks = new Task[10];
        
        for (int i = 0; i < 10; i++)
        {
            tasks[i] = AddItemAsync("蘋果");
        }
        
        await Task.WhenAll(tasks);
        
        foreach (var item in shoppingList)
        {
            Console.WriteLine($"{item.Key}: {item.Value}");
        }
    }
}

註釋說明:這段程式碼展示瞭如何使用ConcurrentDictionary來安全地在多執行緒環境下新增購物清單項。即使多個執行緒同時嘗試新增“蘋果”,AddOrUpdate方法也會確保不會有重複計數的問題。

總結:

  1. 多執行緒入門:執行緒是程式執行任務的基本單位,多執行緒允許程式同時執行多個任務,如同廚房裡多位廚師同時準備不同菜餚,顯著提升工作效率。透過建立和管理執行緒,你能使程式執行更加流暢,響應更快。

  2. 非同步程式設計與Taskasyncawait關鍵字是C#中非同步程式設計的核心,它們使程式能在等待耗時操作(如網路請求、磁碟I/O)時釋放當前執行緒去做其他工作,如同等待外賣時可以繼續做家務,不白白浪費時間,從而最佳化程式的整體效能。

  3. 併發集合與執行緒安全:在多執行緒環境中,直接訪問共享資料可能導致資料不一致性問題。ConcurrentDictionary等併發集合為此而生,它們內建同步機制,確保了多執行緒訪問時的資料安全,有效避免了競態條件,讓資料操作既高效又可靠。

這些知識點相互支撐,構成了處理併發問題、提升程式效率與穩定性的堅實基礎。掌握它們,你就能在編寫高質量、高效能應用程式的道路上邁出重要一步。

相關文章