併發程式設計——基礎概念(二)

超Code發表於2021-08-06

本文系作者 chaoCode原創,轉載請私信並在文章開頭附帶作者和原文地址連結。

違者,作者保留追究權利。

前言

併發程式設計在我們日常開發中是時時刻刻都有在用的,只不過大部分的程式碼底層已經幫我們去做了一些併發程式設計的安全處理,但是還是有很多情況下需要我們自己去控制,所以我們需要去了解學習併發程式設計,那麼我們一步一步深入的開始學習。
如果有小夥伴沒有看過之前的併發程式設計——基礎概念(一)可以自行觀看。

本篇為概念性的東西,可能比較冗長,請耐心解讀,對於學習併發程式設計之前我們首先要知道這些基本的概念。

基礎概念

1.澄清並行和併發

我們舉個例子,如果有條高速公路 A 上面並排有 8 條車道,那麼最大的並行車 輛就是 8 輛此條高速公路 A 同時並排行走的車輛小於等於 8 輛的時候,車輛就可 以並行執行。CPU 也是這個原理,一個 CPU 相當於一個高速公路 A,核心數或者線 程數就相當於並排可以通行的車道;而多個 CPU 就相當於並排有多條高速公路,而 每個高速公路並排有多個車道。

當談論併發的時候一定要加個單位時間,也就是說單位時間內併發量是多少? 離開了單位時間其實是沒有意義的。

俗話說,一心不能二用,這對計算機也一樣,原則上一個 CPU 只能分配給一個 程式,以便執行這個程式。我們通常使用的計算機中只有一個 CPU,也就是說只有 一顆心,要讓它一心多用同時執行多個程式,就必須使用併發技術。實現併發技術 相當複雜,最容易理解的是“時間片輪轉程式排程演算法”。

綜合來說:
併發:指應用能夠交替執行不同的任務,比如單 CPU 核心下執行多執行緒並非是 同時執行多個任務,如果你開兩個執行緒執行,就是在你幾乎不可能察覺到的速度不 斷去切換這兩個任務,已達到"同時執行效果",其實並不是的,只是計算機的速度太 快,我們無法察覺到而已。

並行:指應用能夠同時執行不同的任務,例:吃飯的時候可以邊吃飯邊打電話, 這兩件事情可以同時執行

兩者區別:一個是交替執行,一個是同時執行。

image.png

2.高併發程式設計的意義、好處和注意事項

由於多核多執行緒的 CPU 的誕生,多執行緒、高併發的程式設計越來越受重視和關注。 多執行緒可以給程式帶來如下好處。

充分利用 CPU 的資源
從上面的 CPU 的介紹,可以看的出來,現在市面上沒有 CPU 的核心不使用多線 程併發機制的,特別是伺服器還不止一個 CPU,如果還是使用單執行緒的技術做思路, 明顯就 out 了。因為程式的基本排程單元是執行緒,並且一個執行緒也只能在一個 CPU 的一個核的一個執行緒跑,如果你是個 i3 的 CPU 的話,最差也是雙核心 4 執行緒的運算 能力:如果是一個執行緒的程式的話,那是要浪費 3/4 的 CPU 效能:如果設計一個多線 程的程式的話,那它就可以同時在多個 CPU 的多個核的多個執行緒上跑,可以充分地 利用 CPU,減少 CPU 的空閒時間,發揮它的運算能力,提高併發量。

就像我們平時坐地鐵一樣,很多人坐長線地鐵的時候都在認真看書,而不是為 了坐地鐵而坐地鐵,到家了再去看書,這樣你的時間就相當於有了兩倍。這就是為 什麼有些人時間很充裕,而有些人老是說沒時間的一個原因,工作也是這樣,有的 時候可以併發地去做幾件事情,充分利用我們的時間,CPU 也是一樣,也要充分利用。

加快響應使用者的時間
比如我們經常用的迅雷下載,都喜歡多開幾個執行緒去下載,誰都不願意用一個 執行緒去下載,為什麼呢?答案很簡單,就是多個執行緒下載快啊。

我們在做程式開發的時候更應該如此,特別是我們做網際網路專案,網頁的響應 時間若提升 1s,如果流量大的話,就能增加不少轉換量。做過高效能 web 前端調優 的都知道,要將靜態資源地址用兩三個子域名去載入,為什麼?因為每多一個子域 名,瀏覽器在載入你的頁面的時候就會多開幾個執行緒去載入你的頁面資源,提升網 站的響應速度。多執行緒,高併發真的是無處不在。

可以使你的程式碼模組化,非同步化,簡單化
例如我們實現電商系統,下訂單和給使用者傳送簡訊、郵件就可以進行拆分, 將給使用者傳送簡訊、郵件這兩個步驟獨立為單獨的模組,並交給其他執行緒去執行。 這樣既增加了非同步的操作,提升了系統效能,又使程式模組化,清晰化和簡單化。

多執行緒應用開發的好處還有很多,大家在日後的程式碼編寫過程中可以慢慢體 會它的魅力。

3.多執行緒程式需要注意事項

執行緒之間的安全性
從前面的章節中我們都知道,在同一個程式裡面的多執行緒是資源共享的,也就 是都可以訪問同一個記憶體地址當中的一個變數。例如:若每個執行緒中對全域性變數、 靜態變數只有讀操作,而無寫操作,一般來說,這個全域性變數是執行緒安全的:若有多 個執行緒同時執行寫操作,一般都需要考慮執行緒同步,否則就可能影響執行緒安全。

執行緒之間的死鎖
為了解決執行緒之間的安全性引入了 Java 的鎖機制,而一不小心就會產生 Java 執行緒死鎖的多執行緒問題,因為不同的執行緒都在等待那些根本不可能被釋放的鎖,從 而導致所有的工作都無法完成。假設有兩個執行緒,分別代表兩個飢餓的人,他們必 須共享刀叉並輪流吃飯。他們都需要獲得兩個鎖:共享刀和共享叉的鎖。

假如執行緒 A 獲得了刀,而執行緒 B 獲得了叉。執行緒 A 就會進入阻塞狀態來等待 獲得叉,而執行緒 B 則阻塞來等待執行緒 A 所擁有的刀。這只是人為設計的例子,但盡 管在執行時很難探測到,這類情況卻時常發生

執行緒太多了會將伺服器資源耗盡形成當機當機
執行緒數太多有可能造成系統建立大量執行緒而導致消耗完系統記憶體以及 CPU 的“過渡切換”,造成系統的當機,那麼我們該如何解決這類問題呢?

某些系統資源是有限的,如檔案描述符。多執行緒程式可能耗盡資源,因為每個 執行緒都可能希望有一個這樣的資源。如果執行緒數相當大,或者某個資源的侯選線 程數遠遠超過了可用的資源數則最好使用資源池。一個最好的示例是資料庫連線 池。只要執行緒需要使用一個資料庫連線,它就從池中取出一個,使用以後再將它返 回池中。資源池也稱為資源庫。

多執行緒應用開發的注意事項很多,希望大家在日後的工作中可以慢慢體會它 的危險所在。

感謝諸君的觀看,文中如有紕漏,歡迎在評論區來交流。如果這篇文章幫助到了你,歡迎點贊?和關注。

相關文章