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

C# 基礎學習:非同步程式設計(二)事件型非同步模式與 BackgroundWorker

     編輯:關於C#

事件型非同步模式 (EAP) 概述

.NET 2.0 引入 EAP,優於 IAsyncResult 模式,廣泛用於各類非同步操作。支援 EAP 的類別特徵:

  • MethodNameAsync 方法啟動非同步作業(可有單一呼叫與多重呼叫兩種多載,後者含 userState 參數區分多次呼叫)。
  • MethodNameCompleted 事件通知完成。
  • CancelAsync 或 MethodNameAsyncCancel 取消作業。
  • ProgressChanged 事件回報進度(含 ProgressPercentage 與 UserState)。

BackgroundWorker 元件

完美實作 EAP,提供:

  • RunWorkerAsync(單一呼叫形式)啟動。
  • RunWorkerCompleted 完成事件。
  • CancelAsync 取消。
  • ProgressChanged 進度事件(需設 WorkerReportsProgress = true)。
  • 額外 DoWork 事件:實際執行邏輯置於此,達成啟動與執行分離。
  • ReportProgress 方法觸發 ProgressChanged。

實作範例:大型文字檔讀取進度顯示

類別結構

class BackgroundWorkerDemo {
    private BackgroundWorker _bw;
    private string _filePath;

    public BackgroundWorkerDemo(string filePath) {
        _filePath = filePath;
        _bw = new BackgroundWorker();
        _bw.WorkerReportsProgress = true;
        _bw.DoWork += Bw_DoWork;
        _bw.ProgressChanged += Bw_ProgressChanged;
        _bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
    }

    public void ReadAsync() {
        if (File.Exists(_filePath)) {
            Console.WriteLine("Begin read");
            _bw.RunWorkerAsync();
        } else throw new FileNotFoundException(_filePath);
    }
}

DoWork:讀取檔案並回報進度

private void Bw_DoWork(object sender, DoWorkEventArgs e) {
    long length;
    using (StreamReader sr = new StreamReader(_filePath)) {
        length = sr.ReadToEnd().Length; // 先取得總長度(註:效能可優化)
    }
    using (StreamReader sr = new StreamReader(_filePath)) {
        long onePercent = length / 100;
        long pos = 0;
        int percent = 0;
        while (!sr.EndOfStream) {
            sr.Read(); pos++;
            while (pos > onePercent * percent) {
                ((BackgroundWorker)sender).ReportProgress(percent++);
            }
        }
        e.Result = pos; // 傳遞總字元數給 Completed 事件
    }
}

ProgressChanged:顯示進度百分比

private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e) {
    Console.WriteLine("Reading: " + e.ProgressPercentage + "%");
}

RunWorkerCompleted:處理結果與錯誤

private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
    if (e.Error != null)
        Console.WriteLine("Error: " + e.Error.Message);
    else if (e.Cancelled)
        Console.WriteLine("Work cancelled");
    else
        Console.WriteLine("Finished. Length: " + e.Result);
}

Main 程式

static void Main() {
    Console.Write("Input file path: ");
    string path = Console.ReadLine();
    new BackgroundWorkerDemo(path).ReadAsync();
    Console.ReadLine(); // 阻塞主執行緒等待完成
}

比較與心得

  • 委派 BeginInvoke/EndInvoke 實作 APM 模式與 BackgroundWorker 實作 EAP 結構相似,皆為非同步模式的範本。
  • 效能要求不高的場合,善用委派與 BackgroundWorker 即可簡單有效完成開發。
  • 檔案長度取得部分(ReadToEnd)效能不佳,後續可改用 FileStream.Length 或非同步 I/O 優化。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved