最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

談?wù)剬?GMP 的簡單認(rèn)識

2023-08-23 21:43 作者:阿兵云原生  | 我要投稿

猶記得最開始學(xué)習(xí) golang 的時候,大佬們分享 GMP 模型的時候,總感覺云里霧里,聽了半天,并沒有一個很清晰的概念,不知 xmd 是否會有這樣的體會

雖然 golang 入門很簡單,但是對于理解 golang 的設(shè)計思想和原理,還是需要一定時間的積累和沉淀,更多的應(yīng)該是思想上的沉淀

希望這篇文章能夠?qū)δ懔私?golang 的 GMP 模型有一點幫助

文章分別從一下三個方面來談?wù)勎覍?GMP 模型認(rèn)識

  • golang 中調(diào)度器的變化及其作用

  • 有了進(jìn)程,線程,為什么會出現(xiàn)協(xié)程

  • GMP 模型中的 G,M,P 分別都做著什么樣的事情

golang 中的調(diào)度器的變化及其作用

調(diào)度器,scheduler

怎么理解呢?調(diào)度器就像是一個管理者,負(fù)責(zé)安排事項,負(fù)責(zé)調(diào)度不同人在指定時間在某個崗位上完成自己的價值交付

正如 linux 調(diào)度器一樣,將就緒的進(jìn)程調(diào)度成執(zhí)行狀態(tài),或者將執(zhí)行狀態(tài)的進(jìn)程,打斷,變成阻塞狀態(tài),再變成就緒狀態(tài)

比如說一個經(jīng)典的單進(jìn)程 和 多進(jìn)程/多線程的操作系統(tǒng),

我們可以看到在單進(jìn)程系統(tǒng)中,只需要無腦的將進(jìn)程串行排列好, CPU 會串行去執(zhí)行任務(wù),如果遇到進(jìn)程1 阻塞的情況,其他進(jìn)程也沒有辦法被 cpu 執(zhí)行,那么進(jìn)程2 ,進(jìn)程3 ,進(jìn)程4 就都要等待前面的進(jìn)程完成執(zhí)行完畢,才能到自己執(zhí)行

可以看出單進(jìn)程對于 CPU 的使用過于任性,浪費 CPU 的資源,演進(jìn)到多進(jìn)程/多線程操作系統(tǒng)的時候,就出現(xiàn)了調(diào)度器

上圖中我們可以對比看到,在多進(jìn)程/多線程的操作系統(tǒng)中,cpu 的時間片被分割的更加的小,對于 cpu 資源的利用率是大大的增加了,因為 cpu 可以在進(jìn)程1阻塞的時候,切換去執(zhí)行進(jìn)程2

例如,當(dāng)進(jìn)程1 執(zhí)行過程中,發(fā)生了阻塞,那么調(diào)度器就會就會將 cpu 切換到進(jìn)程2 中進(jìn)行執(zhí)行,同理,進(jìn)程2 阻塞的時候, cpu 就會被切換到進(jìn)程 3 進(jìn)行執(zhí)行,當(dāng)然,這就看是哪個進(jìn)程先搶到 cpu 資源了

可以看到,調(diào)度器在這里的作用就是最大限度的利用上 CPU 的資源,管理進(jìn)程在 CPU 上按照一定的的順序執(zhí)行任務(wù),就好比一個優(yōu)秀的管家可以合理安排好不同的員工在指定的時間上專注的處理某項事務(wù)

那么 golang 的調(diào)度器是不是也是和 linux 中的調(diào)度器有著想通之處呢?

來看看調(diào)度器在 golang 中的具體作用是干啥的

在 golang 中,調(diào)度器的實現(xiàn)簡單來看實際上是由協(xié)程和線程按照一定的邏輯來組合起來的,其實也是扮演著一個協(xié)調(diào)和調(diào)度的作用,調(diào)度的對象是協(xié)程和線程,協(xié)程是需要被調(diào)度到線程中來運行的,這個動作就是調(diào)度器干的

  • 通常用 G 來表示協(xié)程

  • 用 M 來表示線程

正如是這樣來實現(xiàn)調(diào)度器的:

我們可以看到,當(dāng)每一個 M 想要從全局隊列中取 G 出來執(zhí)行的時候,是需要訪問全局隊列的鎖,這是一把互斥鎖,同一時間只能有 1 個 M 在訪問

Golang 的調(diào)度器此處當(dāng)然也能讓多個 M 處理不同的 G,達(dá)到多進(jìn)程/多線程 并發(fā)處理事項的目的

可我們知道,加鎖,是會影響到我們系統(tǒng)的整體性能的,畢竟那么多 M 都在競爭這一把鎖,勢必同一時間沒有搶到的鎖的 M 就要等待了

為什么調(diào)度器會被淘汰掉?

看到上圖,細(xì)心的我們可以發(fā)現(xiàn),

所以,這個調(diào)度器缺點也是比較明顯的:

第一,多個 M 都要并發(fā)的去獲取全局隊列中的 G ,會造成鎖競爭 , 此處操作全局隊列的情況有如下幾種情況

  • 創(chuàng)建 G

  • 調(diào)度 G

  • 銷毀 G

第二, 線程 M 在執(zhí)行 G 的過程中,如果 G 阻塞了,那么 M 也就阻塞了,這個時候,CPU 就需要切換到其他的 M 上執(zhí)行 G,這個切換的過程也是對于 CPU 資源的浪費

正如人的大腦,同時處理多個事項,當(dāng) 事項 1 未處理完畢,就去處理事項 2,那么需要重新理清思緒去執(zhí)行,若這個時候又需要切換到 事項 1 的時候,就需要花更多的時間來回顧之前事項 1 處理的上下文了, 所以在工作中,沒有特別必要,不要打擾別人

第三, 我們知道在 golang 中,一個 G 也是可以再創(chuàng)建 G 的,就叫 G1 吧,那么創(chuàng)建的這個 G1 就需要交給其他的 M 來進(jìn)行執(zhí)行了,因為當(dāng)前的 M 正在執(zhí)行 G,自己忙不過來,因此需要將 G1 交給 M1 執(zhí)行

這也是一個很明顯的問題

正如上述例子一樣, 2 個人排查相關(guān)問題,但是信息和認(rèn)知不一致,很明顯是小豬可能是比較難排查出問題來的

就像 M 執(zhí)行 G 新創(chuàng)建了 G1,但是是交給 M1 來執(zhí)行的, M1 并不知道 G1 和 G 的關(guān)系,M1 執(zhí)行起來就可能會出現(xiàn)問題,例如需要 G 的一些上下文,但是 M1 并不知情

因此,隨著時間的推移,對于性能的要求是越來越高,當(dāng)然是要想辦法換一個與時俱進(jìn),需要符合時代潮流的管家了,自然就出現(xiàn)了一個新的調(diào)度器替代了原有的調(diào)度器

出現(xiàn)新的調(diào)度器,自然是解決了舊的調(diào)度器的缺點,并且還帶來了一些新的屬性和價值,具體的新調(diào)度器策略我們可以在下文中進(jìn)行展示

為什么會出現(xiàn)協(xié)程

在來看另外一個問題,為什么會出現(xiàn)協(xié)程,自然是因為使用進(jìn)程和線程不能夠滿足我們的某些需求了,此處的需求是指對于性能的要求,是對 CPU 利用效率的需求

上圖中我們有說到,對于多進(jìn)程/多線程并發(fā)的時候,我們有提高 CPU 的利用率,盡可能的利用好 CPU 的時間片,但是對于 CPU 從 進(jìn)程/線程1 切換到去執(zhí)行進(jìn)程/線程 2 的過程中,是會產(chǎn)生消耗的,但是這個消耗很難避免

那么我們知道 CPU 其實執(zhí)行的是線程,那么如果 1 個線程里面還可以分成多個程序進(jìn)行并發(fā)豈不是可以大大的提高我們當(dāng)前線程的使用效率?

我們從 C/C++ 中知道,咱們的一個32位系統(tǒng)的機(jī)器,進(jìn)程實際上是開辟了一個 4G 的虛擬空間,具體 4G 虛擬空間都包含了什么,我們可以簡單的看看這個圖,本次不在此細(xì)聊

那線程大概也是需要 4M 的空間,那么我們在一定程度上大量的開辟進(jìn)程或者線程,必然會帶來系統(tǒng)中 內(nèi)存占用高,調(diào)度 CPU 切換的消耗高 的問題

后來,我們知道線程實際上是分為內(nèi)核態(tài)和用戶態(tài)的

當(dāng)然,用戶態(tài)的線程是依賴于內(nèi)核態(tài)線程的,用戶態(tài)中需要執(zhí)行的內(nèi)容,是需要放在內(nèi)核態(tài)線程上進(jìn)行執(zhí)行的,另外, CPU 只知道有內(nèi)核態(tài)線程的存在,意味著,CPU 只認(rèn)內(nèi)核態(tài)線程

此處說的內(nèi)核態(tài),和用戶態(tài),其實就是對應(yīng)到我們說的 M 和 G

  • 內(nèi)核態(tài)線程 -- 線程

  • 用戶態(tài)線程 -- 協(xié)程

協(xié)程不會陷入到內(nèi)核態(tài)中,因此在 M 不變的情況下,切換 G 就是非常輕快的了,協(xié)程簡要有如下特點:

  • 占用內(nèi)存空間小,只占用 幾 kb ,比起進(jìn)程,線程來說,真的是很小了

  • 調(diào)度靈活,他是處于用戶態(tài)進(jìn)行調(diào)度的

根據(jù)協(xié)程和線程處于的用戶態(tài)和內(nèi)核態(tài),我們可以看到調(diào)度的機(jī)制是不一樣的,

內(nèi)核態(tài)中的線程,實際上是搶占式的,是又 CPU 調(diào)度的

用戶態(tài)中的線程,即協(xié)程,是由用戶態(tài)調(diào)度的,此處的用戶態(tài)調(diào)度,就可以理解是一個隊列了,只能一個一個的去執(zhí)行了,一個協(xié)程執(zhí)行完畢之后,讓出 CPU ,才會執(zhí)行下一個協(xié)程

好比我們代碼中,多個協(xié)程,其中 1 個協(xié)程 panic 了,如何不捕獲的話,是不是整個程序都崩潰了

對于 CPU 只認(rèn)內(nèi)核態(tài)線程這一點,咱理解起來就想到與一個公司的老板,只認(rèn)每個產(chǎn)品線上的總監(jiān)一樣,你這個主管后面不管有多人少人在干活,老板只認(rèn)為是你這個主管在干活

當(dāng)然一個公司也不僅僅只有 1 個老板,就像計算機(jī)系統(tǒng)里面也會有多個 CPU ,但是道理是一樣的

如何理解 GMP 模型

GMP 分別表示 協(xié)程 goroutine,線程 thread,處理器 processor

他們?nèi)M成了新的調(diào)度器,他們?nèi)叩年P(guān)系這樣的

咱們從圖中可以知道有全局隊列,本地隊列

全局隊列還是和之前一樣,從里面里面 G 的創(chuàng)建,調(diào)度,銷毀 都是需要訪問互斥鎖的

P 的本地隊列 自己維護(hù)了一個 G 列表,最長是 256 個那 P 的個數(shù)一般是 GOMAXPROCS 個,如果本地的隊列滿了,那么 P 會將隊列中的一半給到全局隊列中

從本地隊列中取 G 是不需要加鎖的,直接取即可,且如果隊列中的 G 又創(chuàng)建了 G1 ,那么這個 G1 也是會被優(yōu)先加入到當(dāng)前本地隊列的

此處我們可以看到 M 是和 P 進(jìn)行對應(yīng)了,當(dāng) M 需要運行 G 的時候,就需要先找到一個合適的 P ,從 P 中獲取 G, 如果 P 為空,那么 M 就會從全局隊列中獲取一批 G 放到 P 的隊列中

或者是 M 也會從其他的 P 的隊列中偷一半的 G 到當(dāng)前 P 的隊列中

從這里我們可以知道,新的調(diào)度器,已經(jīng)解決了舊的調(diào)度器的一部分問題了(不需要每次都去找全局隊列)

那么 P 是啥時候創(chuàng)建,創(chuàng)建多少個?M 又是啥時候創(chuàng)建的,創(chuàng)建多少個呢? P 和 M 在數(shù)量上有必然聯(lián)系嗎?

P 是在程序啟動的時候,讀取環(huán)境變量中 GOMAXPROC ,來創(chuàng)建具體 P 的個數(shù)

M 的創(chuàng)建實際上是,若 P 中有很多任務(wù) G ,如果有空閑的 M,那么 P 就會找任意空閑 M 來進(jìn)行處理,如果沒有空閑的 M ,那么調(diào)度器就會去創(chuàng)建 M 來執(zhí)行 P 中的 任務(wù)

那么新的調(diào)度器還有哪些優(yōu)勢呢?

第一

提高了線程的復(fù)用率,如果當(dāng)前線程執(zhí)行完當(dāng)前 P 的任務(wù)之后,當(dāng)前的 M 會嘗試去偷其他 P 里面的 G 來進(jìn)行執(zhí)行,這樣我們就盡可能的避免了線程的創(chuàng)建,銷毀帶來的開銷

第二

如果當(dāng)前的 M 在執(zhí)行 G 的時候,出現(xiàn)了阻塞,那么 M 也會很懂事的讓出當(dāng)前的 P,讓其他 M 來執(zhí)行 P 中的任務(wù),當(dāng)前的 M 就繼續(xù)處理當(dāng)前的 G

第三

上述我們說到當(dāng)前 M 會去從其他 P 的隊列中偷 G,這個是在當(dāng)前 M 對應(yīng)的 P 中沒有 G 的時候,優(yōu)先去做的事情, 如果其他的 P 也沒有 G 的時候,當(dāng)前 M 才會去全局隊列中拿

從這里就可以開始,新的調(diào)度器,已經(jīng)是在大大的弱化了全局隊列的作用

本次先聊到這里,相信你對 GMP 的基本理論也有一些了解了吧

感謝閱讀,歡迎交流,點個贊,關(guān)注一波 再走吧


談?wù)剬?GMP 的簡單認(rèn)識的評論 (共 條)

分享到微博請遵守國家法律
静安区| 包头市| 普兰店市| 扎囊县| 广丰县| 金华市| 成武县| 广丰县| 古丈县| 九江县| 德江县| 潮州市| 固镇县| 防城港市| 惠来县| 旬邑县| 烟台市| 大悟县| 莫力| 宁海县| 巍山| 彩票| 浦北县| 忻城县| 弥勒县| 扎赉特旗| 阳城县| 靖西县| 隆昌县| 合作市| 宜兴市| 绥德县| 儋州市| 丰都县| 康定县| 博白县| 临湘市| 平舆县| 二连浩特市| 陇西县| 衡南县|