實質上鼓勵一下吧

最近重新檢視一些程式,物件一多起來越寫越覺得心虛,總覺得程式變得有點混亂。整理的過程中發現一些特殊的方法,慢慢的釋出已經定案的。

以前在用[VB.NET實現多執行緒]這篇文章裏面描述了多執行緒的寫法,如果只是一個那也就直接利用就好了,複製貼上還是蠻簡單的,在整理類神經網路時,試著使用多執行緒去實現它,速度的確提高不少,但程式碼就是覺得不漂亮,於是發明了這個類別。

   1: public class ThreadLocker {
   2:     private int _threadsCount = 0;
   3:     private int _completeCount = 0;
   4:  
   5:     public ThreadLocker(int threadsCount) {
   6:         _threadsCount = threadsCount;
   7:     }
   8:  
   9:     public void ThreadComplete() {
  10:         _completeCount++;
  11:     }
  12:  
  13:     public int ThreadsCount {
  14:         get {
  15:             return _threadsCount;
  16:         }
  17:     }
  18:  
  19:     public int CompleteCount {
  20:         get {
  21:             return _completeCount;
  22:         }
  23:     }
  24:  
  25:     public bool IsComplete {
  26:         get {
  27:             System.Threading.Thread.Sleep(1);
  28:             return _completeCount == _threadsCount;
  29:         }
  30:     }
  31: }

 

由於我經常遇到的都是有一大批工作要全部做完,在全部做完之後再繼續執行其他工作,而這些工作是不會互相干擾的,因此利用多執行緒來完成它是比較有效率的方法。ThreadPool這個物件有點隊列(Queue)的效果,因此我可以將所有的工作一股腦的全部丟進ThreadPool裏面去,然後等待它做完。當然過程中免不了的會有鎖定的需求,至少執行狀態應該要提供給介面吧,一個簡單的範例如下:

   1: ThreadLocker trainingLocker;
   2:  
   3: public bool Training(int maxCycle, double maxAbsDiffent) {
   4:     trainingLocker = new ThreadLocker(sampleCount);
   5:     for (int sampleNo = 0; sampleNo < sampleCount; sampleNo++) {
   6:         ThreadPool.QueueUserWorkItem(new WaitCallback(TrainingThread), sampleNo);
   7:     }
   8:     while (trainingLocker.IsComplete == false) ;
   9: }

 

這個程式是類神經網路的批次訓練主回圈,只有摘要出跟多執行緒有關的部份,第一行是個物件變數,宣告一個前面所定義的類變數,把它放在類層級是要讓執行緒可以進行鎖定。第二行實例化這個類,並且告訴它總共有多少個工作要進行。

接著是個訓練過程,透過回圈產生執行緒,丟進ThreadPool裏面,然後第八行等待所有執行緒完成。其實這一行可以寫成一個方法WaitAll,但是往往在這個時候需要將執行狀態往前端送,例如已完成多少等等,所以沒有寫成一個固定的方法。

   1: public void TrainingThread(object arg) {
   2:     int sampleNo = (int)arg;
   3:     using (Runner runner = new Runner(this.Network, _fixer, this.Argument.TransferType)) {
   4:         runner.Summation(this.Datas.InputLearnDatas[sampleNo]);
   5:         runner.CalcDiffentRate(this.Datas.StandLearnDatas[sampleNo]);
   6:         runner.SaveFixValue(_learnSpeed, this.Datas.InputLearnDatas[sampleNo]);
   7:     }
   8:     lock (trainingLocker) {
   9:         trainingLocker.ThreadComplete();
  10:     }
  11: }

接著是執行緒的內容,重點在第八行,鎖定trainingLocker物件,告訴它執行緒已經執行完成,這裡也可以進行一些狀態更新的動作。

雖然只是改了一點點東西,卻可以讓程式碼更加規範化,而且不用想太多,就是一個模型複製貼上改改變數就可以用了。

創作者介紹

人生四十宅開始 二號宅

漠哥 發表在 痞客邦 留言(2) 人氣()


留言列表 (2)

發表留言
  • 白色小黑狗
  • 請問一下,一般來說幾個thread適合呢?
    因為我似乎用太多Thread他就會產生無法回應的狀態,整個就當掉了。
  • 會產生無法回應的狀況很多,不過通常跟Thread數量并沒有很大的關係,我的實驗模型是10萬個Thread丟進ThreadPool去執行也沒有產生無法回應的狀況。如果是Win32呼叫,那就要用Application.DoEvents的方式讓你的應用程式才有機會刷新畫面。可以在等待執行緒完成的回圈觸發事件,或者是直接在WinForm上用
    Timer去定期執行DoEvent,這樣應用程式才有空閒時間去刷新視窗。如果還有問題應該就是你的程序進入死回圈,試著拆解為單一執行緒確定沒有問題再試試看吧。

    漠哥 於 2011/11/06 23:56 回覆

  • 白色小黑狗
  • 感謝你!
    我猜可能是遇到DeadLock了
    因為我在程式內有一直使用到Process呼叫執行.bat檔,因此我猜測可能是在執行Process那邊造成的。
    再次感謝您!