.NET進階篇06-async異步、thread多線程1

知識需要不斷積累、總結和沉澱,思考和寫作是成長的催化劑
異步多線程挺大一塊內容,既想拆開慢慢學,又想一股腦全倒出。糾結再三,還是拆開吃透,也不至於篇幅過長,勸退許多人
本篇先做一個概述,列明一些基本概念

一、進程和線程

1、進程

我們打開計算機的任務管理器,會發現系統的很多個進程,每個進程獨佔CPU、內存、磁盤、網絡等資源,是資源分配的最小單元。**多個進程之間是資源隔離**的,數據之間不能直接傳遞。一個exe運行一次就會產生一個進程,運行多次就多個,但他們之間數據互相隔離
在這裏插入圖片描述

2、線程

同樣在任務管理器中我們也能看到線程,一個進程是由多個線程組成的,且至少是由一個線程,那就是主線程。圖中就可以看到線程的數量要比進程大的多
在這裏插入圖片描述

多線程

衡量一個人幹活快,要麼是一件事幹的很快,要麼是他能同時幹很多事。計算機就是如此,以單核CPU類比單個人,理論上單位時間上只能運行一個進程裏一個線程,只能幹一件事。但線程有可能在某些操作比如讀寫磁盤時會等待,這時候磁盤在瘋狂的運轉,CPU卻是閒置狀態,直到磁盤讀寫完成才CPU才繼續工作,所以空閒的這個時候它可以先去幹別的事情,看起開就像單核它也可以同時幹很多事

一個人可以把水壺燒上水的同時去拖地,同一時刻一個人是隻能幹一件事的,只是在快速的頻繁切換,拖地時一直想着水開了沒開了沒,但如果處理不當,多線程效率還低,就像你沒來及去倒已經燒開的水導致幹鍋,還有些任務同時起來更費時,就像你一邊拖地一遍廣播體操一樣,伸展運動123然後拖一下地,然後接着,唉?到哪裏了…

後臺線程

後臺線程不會阻止進程的關閉。當某個程序的所有前臺線程完成後,進程就終止程序退出了,當然後臺線程也會隨即停止。在.NET中用**Thread創建的線程默認都是前臺線程,用線程池、BeginXXX**等啓用的線程都是後臺線程

3、簡言之

線程是獨立執行單元,同一段代碼(參數不同,任務不同)可以交給多個線程去執行,從宏觀上看就是並行的執行,微觀上時間片上還是串行執行的。但多核CPU就另說了,像多個人一樣,一個人負責做飯,一個負責拖地

多線可以提高CPU的利用率,一個線程等待時,可以先去執行其他的任務,當然,線程之間的切換也是需要消耗資源的,開發複雜度也是會變大的,資源爭奪也需要做合理的控制,也並不是所有的任務都適合多線程

4、適用場景

後臺執行耗時任務,前臺界面仍需要友好的展示。在WinForm中,如果單線程(也就是主線程)如果執行耗時的操作,那麼界面就會失去響應,它忙於後臺的任務,無法更新用戶界面的交互。這個時候可以另開一個工作線程來處理耗時的任務,主線程可以響應用戶操作,也可以隨時改變任務的狀態

在沒有界面的程序裏,當一個任務有**潛在的耗時**時,比如等待遠程服務器的響應返回,用工作線程來完成任務可以讓主線程去做其他事情

複雜的計算,多線程在多核CPU上可以更快的完成任務。總之一切都是爲了**效率**,.NET中很多暗中的多線程,比如timer,backgroudworker,webservices等,我們使用中自然而然就在利用其多線程帶來的好處,在瞭解了基本原理後,我們需要手動創建管理明面上的多線程任務

多線程縱然可以提高你的程序流暢度,但開發調試中確實增大了難度,一方面除了要對業務劃分適應多線程的處理模式,另一個方面多線程最終還是交於操作系統的調度,我們雖可以執行一些優化調度,但最終結果並不是總盡人意,線程之間的切換也會消耗資源,所以多線程的設計應該儘量簡單

二、同步和異步

1、同步

同步方法調用在程序繼續執行之前需要等待同步方法執行完畢返回結果,程序自上而下順序執行,沒完成一個指令,在進行下一個指令。在代碼調試的表現爲,光標一步一步完成上一步計算後,纔會進入下一行。**阻塞**調用線程的運行

2、異步

異步方法則在被調用之後,調用線程不會等待方法的完成,會直接進入下一行,執行下一個指令,所以是**非阻塞**的

3、異步編程

.NET通過委託可以實現異步調用任何方法。像上面介紹委託方法調用時,除了Invoke同步方法,還有BegInvoke異步方法,它會啓用一個異步調用線程,你只需要傳入委託方法的參數(可能還需要線程額外參數,如果有必要的話)就可以以後臺線程的方式執行方法。在代碼上執行到BeginInvoke時,會立即返回,不等待異步調用的完成,它返回一個IAsyncResult類型,你可以用它來監視調用的進度。和BegInvoke成對的EndInvoke方法可以用於獲取異步調用的結果,這是會阻塞的。具體將在下一篇代碼實例中講解BeginInvoke的常用套路

4、Async、Await

Async、Await是.NET4.5新增的異步編程方式,爲了簡化異步程序的編寫。上面的說的異步調用方式就是經典的APM異步編程模型,基於IAsyncResult接口實現BeginXXX和EndXXX類似的方法。在.NET4.5中可以使用Async方式,通過Async關鍵字標記方法爲異步方法,然後在方法內部通過await標記後面的方法耗時,調用線程到這裏就回去吧。我們就可以不用APM方式,用async方式可以輕鬆將一個方法編程異步方法

public async void Async1()
{
    HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create("http://cnblogs.com/");
    await myReq.GetRequestStreamAsync();
    //to do
} 

5、異步操作優缺點

異步操作相比較於多線程,減少了死鎖的可能,在設計良好的情況下,異步函數可以不必使用共享變量,可以減少出錯的機率。但起步也是難以調試的,只有儘量減少其複雜度

三、小結

這篇主要介紹一些概念,接下來硬核編碼部分就不會再囉嗦這些,上面有遺漏的,在編碼中會捎帶一些。基本就這些吧,TaskFactory、ThreadPool、Task、Parallel等都是對Thread的封裝,過一遍代碼,瞭解常用方法套路就可以。不會面面俱到每個接口都試一下,微軟官網文檔更全面(吹一波,.NET微軟大佬的技術支持還是槓槓的)。後面主要搞一些成熟的套路,比如線程的同步,線程取消,異常處理,線程安全、鎖機制等可用的編碼方式。

OK,那下期見,去給FPX打氣去,拜了個拜~

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章