C 多執行緒之旅 1 介紹和基本概念

2022-01-10 10:33:48 字數 4422 閱讀 2678

c#多執行緒之旅目錄:

c#多執行緒之旅(1)——介紹和基本概念

c#多執行緒之旅(2)——建立和開始執行緒

c#多執行緒之旅(3)——執行緒池

c#多執行緒之旅(4)——apm初探

c#多執行緒之旅(5)——同步機制介紹

c#多執行緒之旅(6)——詳解多執行緒中的鎖

c#多執行緒之旅(1)——介紹和基本概念

c#通過多執行緒支援並行執行的**。乙個執行緒是乙個獨立執行的路徑,可以同時與其他執行緒一起執行。

乙個c#客戶端程式(console,wpf,winows forms)開始於乙個單獨的執行緒,該執行緒由clr和作業系統自動地建立,我們稱它為主執行緒,而且可以通過建立附加的執行緒來實現多執行緒。

所有的例子都假設引入了以下的namespaces:

一旦開始,乙個執行緒的isalive屬性返回true,直到這個執行緒結束。當傳遞給執行緒的建構函式的委託完成執行時,這個執行緒結束。一旦結束,這個執行緒不能重啟。

clr給每個執行緒分配自己記憶體棧,因此區域性變數可以保持分離。在下乙個例子中,我們定義了乙個

使用區域性變數的方法,然後在主線程和子執行緒同時呼叫這個方法。

1

class

program29

10static

void

go()

1116

}17 }

因為每個執行緒的記憶體棧都有乙份隔離的迴圈變數的拷貝,因此可以推斷出,輸出結果是10個「y」字元。

如果多個執行緒對同乙個物件例項有相同的引用,這些執行緒就共享這個物件例項的資料。例如:

1

class

program211

12void

go()

1319

}20 }

因為兩個執行緒都呼叫例項p的go的方法,因此他們共享done這個字段,結果是done只列印出一次而不是兩次。

靜態字段提供另外一種共享資料的方法:

1

class

threadtest 210

11static

void

go()

1214

}15 }

這兩個例子展示了另外乙個重要的概念:執行緒安全確實是不確定的:done可能被列印出兩次(儘管是不太可能發生的)。當我們把go方法中的語句的順序交換下,列印出兩次done的機率顯著提公升。

1

class

program211

12void

go()

1319

}20 }

改進方式當讀\寫乙個公共欄位時,獲取乙個獨佔鎖(exclusive lock)。c#提供了關鍵字lock。

1

class

program211

12static

void

go()

1321}22

}23 }

當兩個執行緒同時搶占乙個鎖時(在這個例子中,locker),乙個執行緒等待,或者阻塞,知道這個鎖釋放。在這個例子中,這個鎖保證一次只有乙個執行緒可以進入**的臨界區域,然後「done」只會被列印一次。**在這種不確定的多執行緒背景下中被保護被叫做執行緒安全。

注意:在多執行緒中,共享資料是造成複雜原因的主要,而且會產生讓人費解的錯誤。儘管很基本但還是要盡可能保持簡單。

乙個執行緒,當阻塞的時候,不占用cpu資源。

通過呼叫乙個執行緒的join方法,可以等待另外乙個執行緒結束。例如:

1

static

void main(string

args)210

static

void

go()

1116 }

這個會列印字元"y"1000次,然後緊接著立刻列印"thread t has ended!"。join有多個過載方法,可以在join方法中新增乙個引數,milliseconds或者timespan。如果這個執行緒結束了則join方法返回true,如果這個執行緒超時則返回false。

thread.sleep(timespan.fromhours(1));//sleep乙個小時

thread.sleep(500);//sleep 500 微秒

當使用sleep或join暫停執行緒時,這個執行緒是阻塞的,不消耗cpu資源。

thread.sleep(0)立即放棄這個執行緒的時間片,主動交出cpu給其他執行緒。framework 4.0的新方法thread.yield()方法做同樣的事,除了當它僅僅在同乙個程序中時,才會放棄時間片。

sleep(0)或yield()有時候對提公升產品效能有用。而且它們也是診斷工具可以幫助揭開執行緒安全的問題;

如果在**中的任何地方都插入thread.yield(),會造成bug。

1.多執行緒由乙個執行緒排程器來進行內部管理,乙個功能是clr常常委託給操做系統。

乙個執行緒排程器確保所有啟用的執行緒在執行期間被合適的分配,等待或者阻塞的執行緒(比如,乙個獨佔鎖或者等待使用者輸入)不占用cpu資源。

2.在單核電腦上,乙個執行緒排程器讓時間片在每乙個啟用的執行緒中切換。在windows作業系統下,執行緒切換的時間分片通常為10微秒,遠遠大於cpu的開銷時間(通常小於1微秒)。

3.在乙個多核的電腦上,多執行緒實現了乙個混合的時間片和真正的併發,不同的執行緒同時在不同的cpu上執行**。還是存在某些時間片,因為作業系統需要服務它自己的執行緒,包括其他的應用的執行緒。

4.當乙個執行緒的執行被內部因素打斷,比如時間片,則說這個執行緒是搶占式的。在大部分情形下,乙個執行緒不能控制自己何時何地被搶占。

乙個執行緒類似於你的應用程式正在執行的乙個作業系統程序。類似於程序並行執行在一台電腦上,執行緒並行執行在乙個單獨的程序中。程序之間是完全隔離的;執行緒在一定程度上隔離。執行在同乙個應用程式下的執行緒共享堆記憶體。在某種程度上,這就是為什麼執行緒如此有用:乙個執行緒可以在後台取回資料,比如同時另外乙個執行緒正在顯示資料。

多執行緒有許多用途,下面是最通用的:

保持乙個可響應的使用者介面

通過在乙個並行的「worker」執行緒上執行時間消耗的任務,主ui執行緒可以空閒地執行鍵盤或滑鼠事件。

使其他阻塞cpu的執行緒得到最有效的使用

當乙個執行緒正等待另外一計算機或硬體的響應時是非常有用的。當乙個執行緒執行任務時阻塞了,其他執行緒正好可以使用計算機。

並行程式設計

如果工作負荷被共享給正在執行「各個擊破」策略的多個執行緒,則**在多核或多程序中集中計算可以執行得更快。

**執行

在多核的機器上,你有時通過**某些事情需要做,然後提前做,從而可以提高效能。linqpad使用這項技術提高查詢的建立。乙個變體是執行許多並行的演算法去處理同樣的任務。無論哪個完成了第乙個「wins」-當你預先不知道哪乙個演算法執行得更快時,這是非常有效的。

允許同時執行請求

在乙個server上,客戶端請求可以並行抵達,所以需要並行處理。如果你使用asp.net,wcf,web service或remoting,.net framework 會自動建立執行緒。這個在client上也是有用的(比如說處理點對點的net working,或者是user的多個請求)。

比如asp.net和wcf技術,你可能甚至不會注意到,除非你訪問沒有合適的locking,違反執行緒安全的共享資料(假定通過靜態字段)。

多執行緒會帶來一系列問題。最大的問題是多執行緒會提公升複雜性。有許多執行緒本身不會帶來複雜性,而是因為執行緒之間的相互影響(尤其是通過共享資料)。這個適用於是否這個相互影響是故意的,而且這個可以造成長時間的開發周期和乙個持續性的敏感性和不可重現的bug。因為這個原因,需要將相互影響降到最低。盡可能堅持和提高可靠的設計。這篇文章主要集中在處理這些複雜性,移除相互影響這個不用多說。

乙個好的策略是封裝多執行緒的logic到可復用的類中,這些類可以獨立地被測試。這個framework它自己提供了許多的高階執行緒建構函式,我們後面再介紹。

執行緒在排程和切換執行緒時會造成資源和cpu的消耗(當啟用的執行緒數量多餘cpu的核的數量時)-而且有建立/銷毀損耗。多執行緒通常會提公升應用程式的速度-但是如果過度或者不適當使用甚至會使應用程式變慢。比如,當硬體i/o被涉及到時,有兩個執行緒序列執行任務比起10個並行執行緒一次性執行更快。(在等待和脈衝訊號中,我們描述怎樣實現乙個生產者/消費者佇列來實現這個功能。)

Python多執行緒(1) 介紹

python對多執行緒提供了很好的支援,python中多執行緒相關的模組包括 thread,threading,queue。可以方便地支援建立執行緒 互斥鎖 訊號量 同步等特性。1.thread 多執行緒的底層支援模組,除了其中提供的 lock 原語外,一般不建議使用。2.threading 基於 ...

Python多執行緒(1) 介紹

python對多執行緒提供了很好的支援,python中多執行緒相關的模組包括 thread,threading,queue。可以方便地支援建立執行緒 互斥鎖 訊號量 同步等特性。1.thread 多執行緒的底層支援模組,除了其中提供的 lock 原語外,一般不建議使用。2.threading 基於 ...

Storm 1 介紹Storm的基本概念

以分布式併發的方式處理和建立的無限的元組序列。在申明每個流的時候,會給它乙個id識別符號。outputfieldsdeclarerspouts是乙個拓撲裡流的源頭。也就是說,流的起點是spouts。spouts從外部讀入元組資料並將其放入到拓撲中。寫spouts時必須要實現的介面。拓撲中所有的資料處...