多執行緒初探--使用BackgroundWorker(1)

   .Net Framework在多執行緒的支援上提供了許多方便的類別,而BackgroundWorker則是一項非常容易用來撰寫多執行緒的類別, 它不僅和System.Windows.Forms.Timer一樣也在工具箱提供了可拖曳使用的元件,並且提供了ProgressChanged事件使得更動主畫面控制項可以不需藉由Control.Invoke﹝有些時候Invoke的概念對初學者會有或多或少邏輯上的困擾﹞,個人覺得這個元件滿適合初學者當做撰寫多執行緒的入門。

       在MSDN文件庫中是這樣形容BackgroundWorker元件的:﹝引述自 MSDN BackgroundWorker 元件概觀

       BackgroundWorker 元件會提供您在不同於應用程式主要 UI 執行緒的執行緒上,非同步 (「在幕後執行」) 執行耗時作業的能力。若要使用 BackgroundWorker,您只要告訴它要在幕後執行哪種耗時的背景工作方法,然後呼叫 RunWorkerAsync 方法。對執行緒的呼叫會繼續正常執行,直到工作方法非同步執行。當方法完成時,BackgroundWorker 會藉由引發 RunWorkerCompleted 事件來警示呼叫執行緒,此事件會選擇性地包含作業的結果。

       BackgroundWorker的常用屬性:

1. CancellationPending 屬性:﹝Boolean值﹞當BackgroundWorker執行個體呼叫了CancelAsync方法取消背景作業後,這個值會變成true;這個屬性是唯讀的。
2. IsBusy 屬性:﹝Boolean值﹞表示BackgroundWorker執行個體正在執行中;這個屬性是唯讀的。
3. WorkerReportsProgress 屬性 :﹝Boolean值﹞這個值可以設定BackgroundWorker執行個體是否可以藉由呼叫ReprotProgress方法來引發ProgressChanged事件。
4. WorkerSupportsCancellation 屬性 :﹝Boolean值﹞這個值可以設定BackgroundWorker執行個體是否可以藉由呼叫CancelAsync方法來中斷背景作業。

      BackgroundWorker的常用方法:

1. CancelAsync 方法:呼叫這個方法會送出停止背景作業的要求,並將 CancellationPending 屬性設為 true。
2. ReportProgress 方法:呼叫這個方法會引發 ProgressChanged 事件,於是可以將對於主執行緒使用者介面﹝UI﹞控制項的處理程序撰寫於ProgressChanged 事件程序碼中。 如果不熟悉委派與Control.Invoke,以此方法呼叫ProgressChanged是一種不錯的替代方式。
3. RunWorkerAsync 方法 :呼叫這個方法將會引發 DoWork 事件開始執行背景執行緒,需要在背景中執行的程序即可撰寫於DoWork事件程序碼中。這個方法有兩個多載,其中一個多載可以將參數以Object形式傳遞給DoWork事件。

      BackgroundWorker的常用事件:

1. DoWork 事件:將背景執行緒啟動時要執行的程序內容寫在此事件當中。
2. ProgressChanged 事件:在DoWork事件程序中,若有需要更動主畫面控制項時,可以呼叫Reportgress方法來引發此事件,而將控制項更動處理的程序內容寫在此事件中。
3. RunWorkerCompleted 事件:當DoWork作業已完成、取消或引發例外狀況時會引發這個事件。

      先以一最簡單的例子來觀察BackgroundWorker是如何運作的,此程式碼在範例中的Form2。先從工具箱拖曳一個BackgroundWorker元件,並在畫面上布置四個Label物件、一個ProgressBar物件與一個Button物件。為了使得此Backgroundworker可以呼叫ReportProgress方法,故在Form2的Load事件中設定BackgroundWorker1.WorkerReportsProgress = True。接著在Button1的Click事件中撰寫以下程序:

      If BackgroundWorker1.IsBusy = True Then
           MessageBox.Show("背景作業執行中,請稍候!")
       Else
           Label1.Text = "開始於:" & Now().ToString("HH:mm:ss.fffffff")
           BackgroundWorker1.RunWorkerAsync()
           Label2.Text = "Click事件結尾:" & Now().ToString("HH:mm:ss.fffffff")
       End If

     以上這簡單程序的內容表示當按下Button1時先檢查BackgroundWorker1是否正在執行背景作業中,如果為False則在Label1上顯示Button1.Click的時間,接著呼叫RunWorkerAsync方法執行背景作業‧然後在Label2顯示Button1.Click的程序結尾時間。

     在DoWork事件中則撰寫以下程序:

       Dim i As Integer
        For i = 1 To 100
            BackgroundWorker1.ReportProgress(i)   <==呼叫ReportProgress方法以引發ProgressChanged事件,參數為百分比的分子部份。
            System.Threading.Thread.Sleep(10)
        Next

      在ProgressChanged事件中撰寫以下程序:

       ProgressBar1.Value = e.ProgressPercentage  <==依據ReportProgress方法的傳入參數改變Progressbar的Value
       Label3.Text = "進度i=" & e.ProgressPercentage & "/ 時間:" & Now.ToString("HH:mm:ss.fffffff")
<==顯示每一次ProgressBar改變的時間

      在RunWorkerCompletedBKW01事件中撰寫:Label4.Text = "結束於:" & Now().ToString("HH:mm:ss.fffffff")

       整個Form2的程式主要是在彰顯Backgroundworker與主執行緒會在不同步的方式下進行,由左方的圖形可以發現Button1.Click事件在14:53:57.9687500秒就已進行到最後一行﹝和開始於的時間居然還相同,表示中間的過程似乎還小於千萬分之一秒﹞,但整個背景作業依然繼續進行,直到14:53:59.6562500才引發了RunWorkerCompleted事件。

       這個範例的迴圈數因為沒有很多,所以執行的時間也並沒有很長,各位想像一下,如果今天把BackgroundWorker排除,並且將迴圈數放大,以單執行緒的形式來執行這個程式,主畫面就會有一段長時間處於看起來像是已經停止反應的狀態,使用者恐怕很容易誤認程式已經當掉了。所以在遇到這種非不得已要長時工作的程序就非得使用多執行緒的方式來處理會比使用單一執行緒感覺要好一些,而BackkgroundWorker正是提供一個簡單的方式讓初學者容易上手。

這一篇的範例可以在以下連結下載[VB2005]:BackgroundWorkerTest01.rar

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BackgroundWorker是一个多线程组件,可以在后台执行耗时的操作,而不会阻塞UI线程。以下是使用BackgroundWorker的步骤: 1. 在Visual Studio中拖动一个BackgroundWorker组件到窗体或控件中。 2. 设置BackgroundWorker的属性,包括是否支持取消操作、是否报告进度等。 3. 在代码中为DoWork事件编写处理程序,该事件是BackgroundWorker执行耗时操作的地方。在处理程序中执行需要在后台线程中进行的操作。 4. 如果需要报告进度,可以在处理程序中调用ReportProgress方法。在ProgressChanged事件中处理报告的进度。 5. 如果需要支持取消操作,可以在处理程序中检查CancellationPending属性,如果为true,则取消操作。 以下是一个示例,演示如何使用BackgroundWorker执行耗时操作并报告进度: ```csharp private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { int total = 100; for (int i = 0; i < total; i++) { if (backgroundWorker1.CancellationPending) { e.Cancel = true; return; } // 模拟耗时操作 Thread.Sleep(100); // 报告进度 int progress = (int)(((double)i / total) * 100); backgroundWorker1.ReportProgress(progress); } } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar1.Value = e.ProgressPercentage; } private void button1_Click(object sender, EventArgs e) { // 启动后台操作 backgroundWorker1.RunWorkerAsync(); } private void button2_Click(object sender, EventArgs e) { // 取消后台操作 backgroundWorker1.CancelAsync(); } ``` 在上面的示例中,我们在DoWork事件处理程序中模拟了一个耗时操作,使用ReportProgress方法报告进度,并在ProgressChanged事件处理程序中更新进度条。在取消按钮的Click事件处理程序中,我们调用CancelAsync方法取消后台操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值