国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

自以為是的多線程(一)

2019-11-14 13:44:36
字體:
來源:轉載
供稿:網友

    多線程在web開發里面其實應用場景并不多,而且應用到多線程的場景也大多都是一些比較簡單的場景,基本上大多都可以用Task代替,所以很多web開發人員對多線程的理解非常的淺薄,也就導致了會出現很多不可預計的bug,然后又因此寫了一大堆邏輯來繞來繞去,所以我想談談多線程,試圖做到高屋建瓴,給大家一個比較開闊的視野。

    這一篇先從性能角度來說,下一篇從線程安全角度來講解。

    先解釋一下,為什么線程不是越多越好:

    談到多線程必須要談到cpu,一個單核心cpu在同一個時間內,只能執行一個線程(受限于目前技術),對于超線程cpu(intel專利,使用了超線程技術的cpu,容許一個核同時執行兩個線程,在windows操作系統里面也會顯示有兩個核心),我們都理解成是雙核心cpu。

    而對于每個線程,都一定包含以下幾個要素:

    1、線程內核對象,系統為每個線程創建的,包括上下文(context)等。

    2、線程環境塊,是一塊內存,包含線程的異常處理鏈首。

    3、用戶模式棧、內核模式棧。

  4、DLL線程鏈接和線程分離通知

    這個是我們在創建一個新線程時,系統在為線程初始化時需要創建的東西。

    而前面又提到了,一個單核CPU同一時間內只能跑一個線程,那么當一個CPU正在跑一個線程的時候,這個線程的很多數據已經存到了CPU的高速緩存中,這個時候發生了切換,我們需要切換到另外一個線程上面去執行,那這個線程執行的可能是另外的代碼,需要讀取另外的數據,這個時候CPU就需要重新去內存里面去取數據,來填充這個高速緩存。而CPU去內存里面取數據的這個過程,相比于去高速緩存里面取數據來說,是很慢的,這也就是說,當我們頻繁切換線程的話,CPU就需要做很多額外的事情。這也就是說,當只有單核CPU時,同樣的功能,一個線程肯定比多個線程更快。這里有一個矛盾,就是系統不可能只有一個線程,系統還牽涉到很多自己的系統線程,以及其它的應用程序的線程,那系統在做線程切換(系統決定調用哪個線程)的時候,會牽涉到一個線程優先級的問題,而這個調度方法(相對合理智能的一個算法)是我們不可控的,所以說當你的程序有多個線程的情況下,在做線程切換的時候,切換到你的線程上面的概率會變大,所以也不能絕對的說一個線程就一定比多個線程快,這里只是一個大概的相對理論情況。

    既然是這種情況,那我們在寫代碼的時候,就應該盡可能的避免出現線程切換,而讓CPU盡可能的執行該線程。可是在什么情況下會容易出現線程切換(以下所有的線程切換都是指的相對或是可能,因為線程調度不可控)。

    比如我有以下代碼:

public static string ReadText(string path)        {            string text = "";            if (File.Exists(path))            {                using (Stream fs = File.Open(path, FileMode.Open))                {                    using (StreamReader sr = new StreamReader(fs))                    {                        text = sr.ReadToEnd();                        sr.Close();                    }                }            }            return text;        }

    這個是很常見的IO讀取,這個時候會給IO線程發出一個請求,然后等待IO的響應,在等待的過程中,系統會把這個線程鎖定(這是個很棒的設計),讓CPU去做其它事情,等到執行響應完畢以后,再喚醒該線程。同理,在做數據庫的讀取以及一些其他的IO請求時,都會這樣。假如當有一個用戶請求時,我們就會執行這樣一段代碼,那當有不斷多的用戶請求時,系統就會創建不斷多的線程(創建線程的本身開銷就很昂貴),而當IO讀取完響應的時候,又會有不斷多的線程逐漸被喚醒,系統這個時候就又會疲于線程切換,你就會發現性能開始巨降。

同理,當我有以下代碼時:

lock(object){    ...}

當多個線程在執行這段代碼的時候,就會出現很有意思的情況。

假如1-10,一共有10個線程需要執行到這段代碼,假如cpu是2個(分別為A、B,分別執行的是1、2),當1執行的時候,2被鎖定,這個時候B CPU就開始做線程切換,調度3-10中的任意一個繼續執行,如果這段代碼較長,A不一定能在短時間內執行完,那就會出現,調度一個鎖一個,繼續切換,再調度,再鎖定,再切換的一個循環,一直到所有線程都被鎖定為止。

當1執行完畢的時候,這個時候喚醒所有被鎖定的線程,然后重新分配給A、B兩個CPU,然后當A又執行到這里的時候,B又會出現剛剛再調度、再鎖定,再切換這樣的一個循環情況。所以在多線程開發的時候,盡可能的避免共享資源的出現。

 

    ps:那當我們在做多線程開發的時候,什么時候用線程池、什么時候自己寫線程。Task也可以理解為線程池。

    線程池的優勢就是,當邏輯執行完畢以后,并不銷毀線程,而是將線程掛起,當你需要使用線程的時候,就會給你分配一個空閑的線程去執行你的邏輯,讓線程反復使用,因為前面有提到了初始化線程需要創建很多對象,開銷很昂貴。只有當所有的線程都處于繁忙狀態時,沒有線程分配時才去給你重新創建一個新線程。

    可是如果你的程序在某一個時間段有一個峰值的話,那么最繁忙的時候,程序就會創建N多個線程,而當峰值過去了以后,這些被創建的線程不會被釋放掉,會一直占用這你的資源。一直等到GC,才有可能被釋放掉。

    所以各位看客根據自己的業務情況來決定,是否使用線程池。

 

    


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阳新县| 祁门县| 巧家县| 临沭县| 拜城县| 类乌齐县| 东至县| 白城市| 濮阳县| 三门峡市| 仙桃市| 漠河县| 南康市| 万荣县| 桂林市| 新乡县| 忻城县| 浦县| 彰化市| 礼泉县| 阳泉市| 株洲县| 鲁甸县| 大荔县| 广安市| 福鼎市| 奉化市| 海安县| 宁国市| 边坝县| 崇左市| 石楼县| 大城县| 永善县| 莱芜市| 盐源县| 达州市| 会同县| 岳阳市| 阳春市| 仙居县|