實質上鼓勵一下吧

現在程式越寫越大,CPU功能越來越強,要能夠聽充分的利用CPU的能力才能讓我們的程式在複雜的運算下以最快的速度反應,除了在演算法上面下功夫外,最簡單的就是能夠利用多核心CPU的能力,因此會寫多執行緒(大陸稱為多線程)的程式變成現今高級程式設計師必須具備的技能。

既然要討論多執行緒,就必須了解能夠應用多執行緒的場合。最簡單的場合就是有大量同樣的運算方式但是不同的輸入資料需要在極短的時間運算出來,這樣的場合很多,比如說類神經網路、客製化的電子報…等等。或者是需要近乎同時處理大量使用者輸入並且做出反應的場合,例如線上遊戲的某些處理,雖然輸入所要處理的程序可能不同,但是必須能夠快速的反應回饋。

VB.NET內建了多執行緒的類庫,也就是說只要會使用類庫,就可以很容易的寫出多執行緒的程式。要使用類庫首先就是要引入類庫,程式碼如下

Imports System.Threading
 

執行緒所要執行的程式碼必須是一個副程式用SUB宣告的,它也可以是一個類別裡面的一個方法(Mathod當然也是個SUB),但是絕對不能是個函數,因為執行緒建立起來并不會立刻執行,而是丟到一個待執行的序列池裡面,你不可能等待執行緒的函數丟出返回值出來,如果需要返回值就必須放進公用記憶體(可以是記憶體變數或者是資料庫),再經由主執行緒定時或最後去檢查返回值,這個部分後面再談。

舉一個最簡單的程式例子,為避免轉移焦點程式碼只列出最重要的部分。

Dim LockObj As String
Dim JobTotal As Integer
Dim JobDone As Integer

Sub Main()
  For I As Integer=1 To 100
    callBack = New WaitCallback(AddressOf AThread)
    ThreadPool.QueueUserWorkItem(callBack)
    JobTotal += 1
  Next
  'waiting all thread finish
  While (JobDone < JobTotal)            
    Thread.Sleep(500)
  End While
End Sub

Sub AThread()
  SyncLock GetType(LockObj)
    JobDone += 1
  End SyncLock
  Thread.Sleep(100)
End Sub

這樣的寫法在第三行建立了一個執行程式的副本,在第四行的時候把它丟進Threading Pool裡面去,.Net Framework會一次最多執行10個(舉例,這個值可以設定的)執行緒,執行完了的就丟掉,再從Pool裡面取出一個來執行。簡單說這樣做的好處是因為你所建立起來的每一個執行緒都需要一些記憶體,並且執行緒並且會分割CPU的時間,造成CPU必須不斷的在很多的執行緒之間轉換,如果沒有限制同時執行的執行緒,記憶體是個問題,整個電腦的反應速度又是一個問題,如果太多執行緒同時執行,將會造成CPU沒有時間去處理前臺的反應。

副程式Sub AThread裡面就是你要處理的運算內容,Thread.Sleep是暫時的讓這個執行緒休眠100毫秒,這一行是非必要的,加上去只是讓你容易觀察程式的執行結果。

多執行緒還有一個重要的課題,就是記憶體共用的問題,也就是如何使用公用變數。因為執行緒是同時有多個在執行的,有極大的可能同時去存取公用變數,如果只是單純的讀出當然不會有問題,但若是需要變更公用變數的內容,那就需要在使用之前進行鎖定動作,無論是你要讀出或寫入都應該要鎖定,這個鎖定的動作由SyncLock指令所執行,其中LockObj只要是個已存在的物件即可。

要注意的是,這樣的程式並沒有辦法讓你處理不同的資料,也就是說所有的執行緒所做的事情都是一樣的。要處理不同的資料也就是說你必須要傳參數進去,參數的傳法在上面的第四行,改成多加一個參數呼叫ThreadPool,也就是讓ThreadPool在取出來準備執行的時候將我們的參數帶給副程式。

ThreadPool.QueueUserWorkItem(callBack, Arg)
 

而被呼叫的副程式需要增加一個參數輸入

Sub AThread(ByVal Argument As Object)
 

要注意的是這個參數必須是個物件,也就是說你必須為這個參數建立一個類別。而且這個參數是在執行緒執行完了以後就被消滅的,所以是不能有傳回值的。如果需要簡單的傳回值,那麼一種方法就是在主呼叫程式宣告一個陣列,在傳入參數時把陣列的索引值帶過去給他,這樣副程式就能夠依據索引值將返回值存入陣列。如果只是要存值進入返回值陣列裡面的一個元素,那麼在做記憶體鎖定的時候也可以直接用這個元素來當鎖定因子,這樣可以避免因為頻繁的鎖定一大團記憶體造成整個程序變慢。

這是使用VB.NET寫多執行緒程式最簡單的方法,但並不是執行最快速的方法,至於其他的方法有機會再做介紹。如果想要了解更多,可以參考這篇文章

創作者介紹

人生四十宅開始 二號宅

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


留言列表 (3)

發表留言
  • 丫福
  • 執行緒的書

    請問大大..小弟最近在寫執行緒相關的程式..不知是否能介紹幾本..有詳細執行緒及Timer應用的書..感謝~~~
  • 悄悄話
  • UU
  • 受教!