程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> ERP/MIS 開發 多線程模式與應用(開放源碼)

ERP/MIS 開發 多線程模式與應用(開放源碼)

編輯:關於C#
 

先舉一個例子,以幫忙回憶起對多線程的印象。CopyFilesProc是實現拷貝文件的一個方法,用多線程調用:

  Thread simpleThread = new Thread(CopyFilesProc);

  simpleThread.Name = "CopyFiles";

  simpleThread.Start();

啟動調用,在VS2010中,增加了線程調試窗口,以查看當前進程的線程。我的理解是,總是記得給你的線程命名。

image

 

1 需要與界面互動的場景,需要實現報告進度,應用BackgroundWorker組件

image

如圖,月結的界面效果圖,當用戶點擊Process按鈕後,出現進度條,顯示處理進度
對於BackgroundWorker控件的運用,請查閱MSDN知識庫。我這裡對報告進度這一小功能,作說明。

報告進度的功能,分兩種情況來實現。一種是處理任務(Job)沒有用接口實現,當前進度變量存在於窗體中,源碼如下

private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
       {
           bgWorker.ReportProgress(10, fileName);            
        }

直接在DoWork事件中,調用ReportProgress方法,如果可能,還可以傳入變量值

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
       {
           string fileName = e.UserState.ToString();
        }

注冊事件ProgressChanged來輸出當前正在處理的項目,在這個方法中可以操作UI控件。

 

另一種方法是,處理任務的實現(Job的功能實現)被隔離到第三方的類庫中,說白了就是放到外部的類文件中,不與窗體代碼混淆在一起。代碼舉例,對於月結功能,可能的一個這樣的實現

public interface IJob
    {
        void Execute();
     }

實現文件

public class Job : IJob
   {

     public void Execute()
       { 

       }

    }

在窗體的bgWorker_DoWork方法中,調用實現job.Execute()來這現月結功能。

這種方法下,報告進度的功能稍微復雜一點,要用到定時器,進度存放變量值,執行任務時更新進度。
實現步驟如下,在接口實現文件,定義存放進度變量的集合值_JobProcess變量,

public class Job : IJob
   {
       private static ConcurrentDictionary<int, bool> _JobProcess;

在執行長時間任務前,初始化進度變量

public void Execute()
        {
            if (_JobProcess == null || _JobProcess.Count== 0||_JobProcess.Count>0)
            {
                _JobProcess = new ConcurrentDictionary<int, bool>();
                for (int i = 1; i <= _Step; i++)
                {
                    _JobProcess.TryAdd(i, false);
                }
            }

_Step是步長,這裡有簡化處理。實際操作中,要對任務進行分類處理,以達到分步的目的。比如,核算客戶往來帳目,就以客戶為依據來分步長,有121個客戶,這裡_Step就是121,然後每處理完一個客戶的帳目,就把它設置為已經處理,即這樣來調用

for (int i = 1; i <= _Step; i++)
           {
               _JobProcess[i] = true;
               Thread.Sleep(2000);
           }

每處理一個任務,就把它的時度標志為true,以表示已經處理。這樣,在進度反饋接口中,可以及時反饋結果

public object[] GetExecuteStatus()
        {

              //已經處理完成

              int completedCount = (from item in _JobProcess
                                                   where item.Value == true
                                                   select item).Count();

               //當前總任務數量
                int totalCount = (from item in _JobProcess                                
                                  select item).Count();

                //正在處理的任務

                int itemInProcess = (from item in _JobProcess
                                        where item.Value == false
                                        orderby item.Key
                                        select item.Key).FirstOrDefault();

                 }

將這三個值返回到界面的timer的Tick事件中,實時改變界面的ProgressBar的狀態,以達到報告進度的目的。

 

當完成功能需要一定的時間,一般定為超過20second,都應該用BackgroundWorker來處理,以保持界面及時響應。

 

2 不需要界面發生互動,後台運行完成後,顯示結果即可,應用WorkerThreadBase模式

這個模式最主要的實現類是WorkerThreadBase,

public abstract class WorkerThreadBase : IDisposable
    {
        private Thread _workerThread;
        private ManualResetEvent _stopping;
        private ManualResetEvent _stopped;
        private bool _disposed;
        private bool _disposing;

使用了ManualResetEvent來同步多個線程,MSDN中對ManualResetEvent的解釋是:通知一個或多個正在等待的線程已發生事件. 如果不能明白它的意思,就跑一下測試代碼,來看看用途

DummyWorker dummyWorker = new DummyWorker();
dummyWorker.Start();

CopyFileWorker copyFileWorker = new CopyFileWorker(_copyInfo);
copyFileWorker.Start();

//wait for the two threads to finish
WorkerThreadBase.WaitAll(copyFileWorker, dummyWorker);

如代碼所示,創建2個工作線程,工作線程的創建方法如下

public class DummyWorker:WorkerThreadBase
    {
        protected override void Work()
        {

         }

}

繼承於WorkerThreadBase類型,重寫Work方法即可。

當調用WorkerThreadBase.WaitAll停止當前線程,等待所有的線程運行完畢後,然後可以顯示結果。


總結,後一種模式,編程簡單,效率也高一些;在WinForm應用中,也常常在Forms類型的方法中,動態創建BackgroundWorker然後調用它,以保持UI繼續接受用戶輸入。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved