首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 非同步文件操作實戰:從原理到高效能批次圖像處理範例

     編輯:關於C#

在多任務作業系統中,I/O 操作往往是效能瓶頸。同步 I/O 會讓執行緒原地等待,嚴重浪費 CPU 資源;而非同步 I/O 允許執行緒在發起請求後立即轉向他務,透過回呼或 await 續體機制在完成時接收結果,實現真正的併發處理。

Stream 類別的非同步支援機制

Stream 定義了 BeginRead/EndRead、BeginWrite/EndWrite 虛擬方法,派生類(如 FileStream、NetworkStream)需重寫同步 Read/Write 並提供高效非同步實現。預設的非同步包裝器若包裹同步實作,效能反而不升反降,因此正確實現非同步路徑至關重要。

實戰範例:大批量圖像非同步管線處理

以下範例模擬多核心系統並行處理 200 張 512x512 圖像:讀取 → CPU 密集轉換 → 寫入,展示非同步 I/O 配合執行緒池的強大威力。

非同步版核心邏輯

public class BulkImageProcAsync {
    const string BaseName = "tmpImage-";
    const int Count = 200, Pixels = 512*512;
    static int ProcessRepeats = 20;
    static int Remaining = Count;
    static readonly object LockObj = new(), WaitObj = new();
    static readonly PerfTimer Timer = new("Asynchronous Bulk Image Processor");

    sealed class ImageState { public byte[] Pixels; public int Index; }

    static void MakeFiles() { /* 建立 200 個原始圖像檔 */ }

    static void ReadCallback(IAsyncResult ar) {
        var state = (ImageState)ar.AsyncState;
        Console.WriteLine($"Image {state.Index} read {(ar.CompletedSynchronously?"同步":"非同步")}");
        var stream = (Stream)ar.AsyncObject;
        int bytes = stream.EndRead(ar);
        if (bytes != Pixels) throw new Exception("資料長度不符");
        ProcessImage(state.Pixels, state.Index);
        stream.Close();

        // 非同步寫入結果檔
        using var fs = new FileStream($"{BaseName}{state.Index}.done", FileMode.Create, FileAccess.Write, FileShare.None, 4096, true);
        fs.Write(state.Pixels, 0, Pixels);
        fs.Close();

        state.Pixels = null; // 釋放記憶體
        lock (LockObj) {
            if (--Remaining == 0) { lock(WaitObj) Monitor.Pulse(WaitObj); }
        }
    }

    static void ProcessImage(byte[] px, int idx) {
        for (int r=0; r 0;
        if (needWait) { lock(WaitObj) Monitor.Wait(WaitObj); }
        Timer.StopTimer(t); Timer.OutputStoppedTime();
    }
    // Cleanup, Main 等輔助方法略...
}

同步版對比

public class BulkImageProcSync {
    // ... 相同參數定義 ...
    static void ProcessBulk() {
        Console.WriteLine("開始同步批次處理...");
        int t = Timer.StartTimer("Total Time");
        var buf = new byte[Pixels];
        for (int i=0; i

效能洞察與最佳實踐

  • 緩衝區大小:讀取大檔案時使用小緩衝(如 1KB)節省記憶體;寫入時用較大緩衝(4KB+)減少系統呼叫。
  • useAsync=true:FileStream 建構子最後一個參數設為 true 才會真正啟用 OS 級非同步 I/O(IOCP)。
  • 避免執行緒池飢餓:大量並發非同步操作可能耗盡執行緒池,生產環境建議配合 SemaphoreSlim 限制並發度。
  • 現代化改寫:.NET 4.5+ 建議改用 await fs.ReadAsync(...) / WriteAsync(...) 配合 Task.WhenAll,程式碼更簡潔且例外處理更自然。

實測顯示,在磁碟 I/O 為瓶頸時,非同步版本吞吐量可提升 2-5 倍;若 CPU 運算佔比極高,優勢會縮小。掌握非同步 I/O 精髓,是構建高效能 C# 應用的關鍵技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved