一. 背景html
在剛接觸開發的頭幾年裏,說實話,根本不考慮多線程的這個問題,貌似那時候腦子裏也有沒有多線程的這個概念,全部的業務都是一個線程來處理,不考慮性能問題,固然也沒有考慮多線程操做一條記錄存在的併發問題,後面隨着處理的系統業務愈來愈複雜,多線程再也迴避不了了,也就藉此機會深刻研究了一下.Net中的多線程的處理方案。ajax
發如今.Net領域中,多線程的處理大體經歷了這麼幾個階段:Thread→ThreadPool→委託的異步調用→Task→TaskFactory→Parallerl→異步編程模型(async和await)。數據庫
關注我博客的人會發現,早在2017年6月份的時候,就開始整理多線程問題了,大約用了6篇文章的來介紹了.Net中的線程的使用方法,主要是介紹相應類的實例方法的使用,有點幫助文檔的意思了哦,最近多線程使用的至關頻繁,藉此機會從新結合一些實際業務系統介紹一下.Net領域的多線程問題,本次將整合原先的六篇文章(刪除或覆蓋更新)。編程
本質: 充分發掘CPU的性能,把一些並無前後強依賴關係、且耗時代碼塊放到一個新的線程裏去處理,那麼原先按順序執行的業務就會變成並行執行,讓主線程繼續日後執行,節約了時間了,提升了效率。安全
下面補充一下多線程在時間和空間上的開銷:服務器
(一). 時間上:數據結構
①:開啓或銷燬一個線程都會通知進出中的dll程序集,讓這些dll進行相應的操做。多線程
②:時間片切換:4個邏輯處理器(不考慮Inter的超線程技術,一覈對多個線程),同時並行只能處理4個線程,多餘的休眠,不少時候,咱們看似不少線程在並行執行,其實是間歇性的串行。併發
《關於這個說法有異議的話,請留下您的看法,歡迎討論,請勿謾罵》異步
(二). 空間上:
①:用戶模式堆棧,一個線程分配1M的堆棧空間。
②:內核模式的堆棧,用戶模式的參數須要傳遞到內核模式。
③:線程的內核數據結構,會存放一下變量。
二. 概念的梳理
1. 進程、線程和多線程
進程:當一個程序開始運行時,它就是一個進程(或者多個,eg:遊戲),進程包括運行中的程序和程序所使用到的內存和系統資源,而一個進程又是由多個線程組成。
線程:線程是程序中的一個執行流,每一個線程都有本身的專有寄存器(棧指針、程序計數器等),但代碼區是共享的,即不一樣的線程能夠執行一樣的函數。
多線程:多線程是指程序中包含多個執行流,即在一個程序中能夠同時運行多個不一樣的線程來執行不一樣的任務,也就是說容許單個程序建立多個並行執行的線程來完成各自的任務。
2. 多線程的好處和弊端
好處:能夠提升CPU的利用率。在多線程程序中,一個線程必須等待的時候,CPU能夠運行其它的線程而不是等待,這樣就大大提升了程序的效率。(犧牲空間資源,來換取時間)
弊端:
①:線程也是程序,因此線程須要佔用內存,線程越多佔用內存也越多;(佔內存多)
②:多線程須要協調和管理,因此須要CPU時間跟蹤線程; (佔cpu多)
③:線程之間對共享資源的訪問會相互影響,必須解決競用共享資源的問題;(多線程存在資源共享問題)
④:線程太多會致使控制太複雜,最終可能形成不少Bug。(管理麻煩,產生意外bug)
3. 什麼時候建議使用多線程
①. 當主線程試圖執行冗長的操做,但系統會卡界面,體驗很是很差,這時候能夠開闢一個新線程,來處理這項冗長的工做。
②. 當請求別的數據庫服務器、業務服務器等,能夠開闢一個新線程,讓主線程繼續幹別的事。
③. 利用多線程拆分複雜運算,提升計算速度。
4. 什麼時候不建議使用多線程
當單線程能很好解決,就不要爲了使用多線程而用多線程。
5. 同步調用和異步調用
①單線程同步調用:方法從上而下一次執行,一步一步執行,有前後順序。
②異步調用(區別於異步方法):開啓新的線程去執行業務,主線程單獨執行,能夠選擇是否等待子線程執行完後再執行
同步方法 VS 異步方法:
1. 一個誤區:異步方法指的是一些特有的方法(並不開啓新線程),它和開啓一個新的線程好比「不少狀況下咱們會說,開啓一個新的線程去異步調用」,這不是一回事,典型的異步方法,好比js 的ajax請求。
2. 同步方法:咱們平時封裝的一些普通方法大多數都是同步方法,同步方法典型的特色:就是在沒有獲得方法的返回值或者該方法沒有執行完,該調用就須要在這等待,不能繼續執行。
3. 異步方法:異步方法在調用後,調用這在沒有獲得返回結果前,就能夠繼續執行後續業務,異步方法一般是經過通知、回調的方式告訴調用者,無須消耗過多的性能。
舉例1:
$.Post("url",{},function(data){ });
$("#div1").html("");
這兩行代碼,第一行發送異步請求的時候,即便獲得回調返回值,下面清空div1內容的操做一樣也將執行,Post就是異步方法。
舉例2:
先封裝1個方法: function Add(a,b){ 先休眠5s; return a+b}
調用:
Add(1,2);
$("#div1").html("");
這兩行代碼,Add方法就屬於同步方法,因此必須等5s後,Add方法執行完,才能執行下面清空div1內容的操做。
總結:同步方法和異步方法的區別就是:是否須要等待返回結果,才能執行後續操做。
6. 異步多線程的三個特色
①:同步方法卡界面,緣由是主線程被佔用;開啓新線程去異步調用不卡界面,緣由是計算交給了別的線程,主線程空閒.
②:同步方法慢,緣由是隻有一個線程計算;開啓新線程去異步調用快,緣由是多個線程同時計算,可是更消耗資源,不宜太多.
②:異步多線程是無序的,啓動順序不肯定、執行時間不肯定、結束時間不肯定.
三. 系列章節
第一節:複習委託,而且經過委託的異步調用開啓一個新線程和異步回調、異步等待。
第三節:ThreadPool的線程開啓、線程等待、線程池的設置、定時功能。
第四節:Task的啓動的四種方式以及Task、TaskFactory的線程等待和線程延續的解決方案。
第五節:Task構造函數之TaskCreationOptions枚舉處理父子線程之間的關係。
第六節:深刻研究Task實例方法ContinueWith的參數TaskContinuationOptions。
第七節:利用CancellationTokenSource實現任務取消和利用CancellationToken類檢測取消異常。
第八節:Task的各種Task<TResult>返回值以及通用線程的異常處理方案。
第九節:深究並行編程Parallel類中的三大方法 (For、ForEach、Invoke)和幾大編程模型(SPM、APM、EAP、TAP)
第十節:利用async和await簡化異步編程模式的幾種寫法
第十一節:深究用戶模式鎖的使用場景(異變結構、互鎖、旋轉鎖)
第十二節:深究內核模式鎖的使用場景(自動事件鎖、手動事件鎖、信號量、互斥鎖、讀寫鎖、動態鎖)
第十三節:實際開發中使用最多的監視鎖Monitor、lock語法糖的擴展、混合鎖的使用(ManualResetEvent、SemaphoreSlim、ReaderWriterLockSlim)
第十四節: 介紹四大併發集合類並結合單例模式下的隊列來講明線程安全和非安全的場景及補充性能調優問題。
第十五節:深刻理解async和await的做用及各類適用場景和用法
!