欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程-創(chuàng)新互聯(lián)

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

“專業(yè)、務(wù)實(shí)、高效、創(chuàng)新、把客戶的事當(dāng)成自己的事”是我們每一個人一直以來堅(jiān)持追求的企業(yè)文化。 創(chuàng)新互聯(lián)建站是您可以信賴的網(wǎng)站建設(shè)服務(wù)商、專業(yè)的互聯(lián)網(wǎng)服務(wù)提供商! 專注于成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、軟件開發(fā)、設(shè)計(jì)服務(wù)業(yè)務(wù)。我們始終堅(jiān)持以客戶需求為導(dǎo)向,結(jié)合用戶體驗(yàn)與視覺傳達(dá),提供有針對性的項(xiàng)目解決方案,提供專業(yè)性的建議,創(chuàng)新互聯(lián)建站將不斷地超越自我,追逐市場,引領(lǐng)市場!

坐標(biāo)上海松江高科技園,誠聘高級前端工程師/高級 Java 工程師,有興趣的看 JD:https://www.lagou.com/jobs/6361564.html

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

在 《Awesome Interviews》 歸納的常見面試題中,無論前后端,并發(fā)與異步的相關(guān)知識都是面試的中重中之重,《并發(fā)編程》系列即對于面試中常見的并發(fā)知識再進(jìn)行回顧總結(jié);你也可以前往 《Awesome Interviews》,在實(shí)際的面試題考校中了解自己的掌握程度。也可以前往《Java 實(shí)戰(zhàn)》、《Go 實(shí)戰(zhàn)》等了解具體編程語言中的并發(fā)編程的相關(guān)知識。

在未配置 OS 的系統(tǒng)中,程序的執(zhí)行方式是順序執(zhí)行,即必須在一個程序執(zhí)行完后,才允許另一個程序執(zhí)行;在多道程序環(huán)境下,則允許多個程序并發(fā)執(zhí)行。程序的這兩種執(zhí)行方式間有著顯著的不同。也正是程序并發(fā)執(zhí)行時(shí)的這種特征,才導(dǎo)致了在操作系統(tǒng)中引入進(jìn)程的概念。進(jìn)程是資源分配的基本單位,線程是資源調(diào)度的基本單位。

應(yīng)用啟動體現(xiàn)的就是靜態(tài)指令加載進(jìn)內(nèi)存,進(jìn)而進(jìn)入 CPU 運(yùn)算,操作系統(tǒng)在內(nèi)存開辟了一段棧內(nèi)存用來存放指令和變量值,從而形成了進(jìn)程。早期的操作系統(tǒng)基于進(jìn)程來調(diào)度 CPU,不同進(jìn)程間是不共享內(nèi)存空間的,所以進(jìn)程要做任務(wù)切換就要切換內(nèi)存映射地址。由于進(jìn)程的上下文關(guān)聯(lián)的變量,引用,計(jì)數(shù)器等現(xiàn)場數(shù)據(jù)占用了打段的內(nèi)存空間,所以頻繁切換進(jìn)程需要整理一大段內(nèi)存空間來保存未執(zhí)行完的進(jìn)程現(xiàn)場,等下次輪到 CPU 時(shí)間片再恢復(fù)現(xiàn)場進(jìn)行運(yùn)算。

這樣既耗費(fèi)時(shí)間又浪費(fèi)空間,所以我們才要研究多線程。一個進(jìn)程創(chuàng)建的所有線程,都是共享一個內(nèi)存空間的,所以線程做任務(wù)切換成本就很低了。現(xiàn)代的操作系統(tǒng)都基于更輕量的線程來調(diào)度,現(xiàn)在我們提到的“任務(wù)切換”都是指“線程切換”。

進(jìn)程與線程

本部分節(jié)選自 《Linux 與操作系統(tǒng)/進(jìn)程管理》。

在未配置 OS 的系統(tǒng)中,程序的執(zhí)行方式是順序執(zhí)行,即必須在一個程序執(zhí)行完后,才允許另一個程序執(zhí)行;在多道程序環(huán)境下,則允許多個程序并發(fā)執(zhí)行。程序的這兩種執(zhí)行方式間有著顯著的不同。也正是程序并發(fā)執(zhí)行時(shí)的這種特征,才導(dǎo)致了在操作系統(tǒng)中引入進(jìn)程的概念。進(jìn)程是資源分配的基本單位,線程是資源調(diào)度的基本單位

進(jìn)程(Process)

進(jìn)程是操作系統(tǒng)對一個正在運(yùn)行的程序的一種抽象,在一個系統(tǒng)上可以同時(shí)運(yùn)行多個進(jìn)程,而每個進(jìn)程都好像在獨(dú)占地使用硬件。所謂的并發(fā)運(yùn)行,則是說一個進(jìn)程的指令和另一個進(jìn)程的指令是交錯執(zhí)行的。無論是在單核還是多核系統(tǒng)中,可以通過處理器在進(jìn)程間切換,來實(shí)現(xiàn)單個 CPU 看上去像是在并發(fā)地執(zhí)行多個進(jìn)程。操作系統(tǒng)實(shí)現(xiàn)這種交錯執(zhí)行的機(jī)制稱為上下文切換。

操作系統(tǒng)保持跟蹤進(jìn)程運(yùn)行所需的所有狀態(tài)信息。這種狀態(tài),也就是上下文,它包括許多信息,例如 PC 和寄存器文件的當(dāng)前值,以及主存的內(nèi)容。在任何一個時(shí)刻,單處理器系統(tǒng)都只能執(zhí)行一個進(jìn)程的代碼。當(dāng)操作系統(tǒng)決定要把控制權(quán)從當(dāng)前進(jìn)程轉(zhuǎn)移到某個新進(jìn)程時(shí),就會進(jìn)行上下文切換,即保存當(dāng)前進(jìn)程的上下文、恢復(fù)新進(jìn)程的上下文,然后將控制權(quán)傳遞到新進(jìn)程。新進(jìn)程就會從上次停止的地方開始。

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

在虛擬存儲管理一節(jié)中,我們介紹過它為每個進(jìn)程提供了一個假象,即每個進(jìn)程都在獨(dú)占地使用主存。每個進(jìn)程看到的是一致的存儲器,稱為虛擬地址空間。其虛擬地址空間最上面的區(qū)域是為操作系統(tǒng)中的代碼和數(shù)據(jù)保留的,這對所有進(jìn)程來說都是一樣的;地址空間的底部區(qū)域存放用戶進(jìn)程定義的代碼和數(shù)據(jù)。

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

  • 程序代碼和數(shù)據(jù),對于所有的進(jìn)程來說,代碼是從同一固定地址開始,直接按照可執(zhí)行目標(biāo)文件的內(nèi)容初始化。

  • 堆,代碼和數(shù)據(jù)區(qū)后緊隨著的是運(yùn)行時(shí)堆。代碼和數(shù)據(jù)區(qū)是在進(jìn)程一開始運(yùn)行時(shí)就被規(guī)定了大小,與此不同,當(dāng)調(diào)用如 malloc 和 free 這樣的 C 標(biāo)準(zhǔn)庫函數(shù)時(shí),堆可以在運(yùn)行時(shí)動態(tài)地?cái)U(kuò)展和收縮。

  • 共享庫:大約在地址空間的中間部分是一塊用來存放像 C 標(biāo)準(zhǔn)庫和數(shù)學(xué)庫這樣共享庫的代碼和數(shù)據(jù)的區(qū)域。

  • 棧,位于用戶虛擬地址空間頂部的是用戶棧,編譯器用它來實(shí)現(xiàn)函數(shù)調(diào)用。和堆一樣,用戶棧在程序執(zhí)行期間可以動態(tài)地?cái)U(kuò)展和收縮。

  • 內(nèi)核虛擬存儲器:內(nèi)核總是駐留在內(nèi)存中,是操作系統(tǒng)的一部分。地址空間頂部的區(qū)域是為內(nèi)核保留的,不允許應(yīng)用程序讀寫這個區(qū)域的內(nèi)容或者直接調(diào)用內(nèi)核代碼定義的函數(shù)。

線程(Thread)

在現(xiàn)代系統(tǒng)中,一個進(jìn)程實(shí)際上可以由多個稱為線程的執(zhí)行單元組成,每個線程都運(yùn)行在進(jìn)程的上下文中,并共享同樣的代碼和全局?jǐn)?shù)據(jù)。進(jìn)程的個體間是完全獨(dú)立的,而線程間是彼此依存的。多進(jìn)程環(huán)境中,任何一個進(jìn)程的終止,不會影響到其他進(jìn)程。而多線程環(huán)境中,父線程終止,全部子線程被迫終止(沒有了資源)。

而任何一個子線程終止一般不會影響其他線程,除非子線程執(zhí)行了 exit() 系統(tǒng)調(diào)用。任何一個子線程執(zhí)行 exit(),全部線程同時(shí)滅亡。多線程程序中至少有一個主線程,而這個主線程其實(shí)就是有 main 函數(shù)的進(jìn)程。它是整個程序的進(jìn)程,所有線程都是它的子線程;我們通常把具有多線程的主進(jìn)程稱之為主線程。

線程共享的環(huán)境包括:進(jìn)程代碼段、進(jìn)程的公有數(shù)據(jù)、進(jìn)程打開的文件描述符、信號的處理器、進(jìn)程的當(dāng)前目錄、進(jìn)程用戶 ID 與進(jìn)程組 ID 等,利用這些共享的數(shù)據(jù),線程很容易的實(shí)現(xiàn)相互之間的通訊。線程擁有這許多共性的同時(shí),還擁有自己的個性,并以此實(shí)現(xiàn)并發(fā)性:

  • 線程 ID:每個線程都有自己的線程 ID,這個 ID 在本進(jìn)程中是唯一的。進(jìn)程用此來標(biāo)識線程。

  • 寄存器組的值:由于線程間是并發(fā)運(yùn)行的,每個線程有自己不同的運(yùn)行線索,當(dāng)從一個線程切換到另一個線程上時(shí),必須將原有的線程的寄存器集合的狀態(tài)保存,以便 將來該線程在被重新切換到時(shí)能得以恢復(fù)。

  • 線程的堆棧:堆棧是保證線程獨(dú)立運(yùn)行所必須的。線程函數(shù)可以調(diào)用函數(shù),而被調(diào)用函數(shù)中又是可以層層嵌套的,所以線程必須擁有自己的函數(shù)堆棧, 使得函數(shù)調(diào)用可以正常執(zhí)行,不受其他線程的影響。

  • 錯誤返回碼:由于同一個進(jìn)程中有很多個線程在同時(shí)運(yùn)行,可能某個線程進(jìn)行系統(tǒng)調(diào)用后設(shè)置了 errno 值,而在該 線程還沒有處理這個錯誤,另外一個線程就在此時(shí) 被調(diào)度器投入運(yùn)行,這樣錯誤值就有可能被修改。 所以,不同的線程應(yīng)該擁有自己的錯誤返回碼變量。

  • 線程的信號屏蔽碼:由于每個線程所感興趣的信號不同,所以線程的信號屏蔽碼應(yīng)該由線程自己管理。但所有的線程都共享同樣的信號處理器。

  • 線程的優(yōu)先級:由于線程需要像進(jìn)程那樣能夠被調(diào)度,那么就必須要有可供調(diào)度使用的參數(shù),這個參數(shù)就是線程的優(yōu)先級。

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

線程模型

線程實(shí)現(xiàn)在用戶空間下

當(dāng)線程在用戶空間下實(shí)現(xiàn)時(shí),操作系統(tǒng)對線程的存在一無所知,操作系統(tǒng)只能看到進(jìn)程,而不能看到線程。所有的線程都是在用戶空間實(shí)現(xiàn)。在操作系統(tǒng)看來,每一個進(jìn)程只有一個線程。過去的操作系統(tǒng)大部分是這種實(shí)現(xiàn)方式,這種方式的好處之一就是即使操作系統(tǒng)不支持線程,也可以通過庫函數(shù)來支持線程。

在這在模型下,程序員需要自己實(shí)現(xiàn)線程的數(shù)據(jù)結(jié)構(gòu)、創(chuàng)建銷毀和調(diào)度維護(hù)。也就相當(dāng)于需要實(shí)現(xiàn)一個自己的線程調(diào)度內(nèi)核,而同時(shí)這些線程運(yùn)行在操作系統(tǒng)的一個進(jìn)程內(nèi),最后操作系統(tǒng)直接對進(jìn)程進(jìn)行調(diào)度。

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

這樣做有一些優(yōu)點(diǎn),首先就是確實(shí)在操作系統(tǒng)中實(shí)現(xiàn)了真實(shí)的多線程,其次就是線程的調(diào)度只是在用戶態(tài),減少了操作系統(tǒng)從內(nèi)核態(tài)到用戶態(tài)的切換開銷。這種模式最致命的缺點(diǎn)也是由于操作系統(tǒng)不知道線程的存在,因此當(dāng)一個進(jìn)程中的某一個線程進(jìn)行系統(tǒng)調(diào)用時(shí),比如缺頁中斷而導(dǎo)致線程阻塞,此時(shí)操作系統(tǒng)會阻塞整個進(jìn)程,即使這個進(jìn)程中其它線程還在工作。還有一個問題是假如進(jìn)程中一個線程長時(shí)間不釋放 CPU,因?yàn)橛脩艨臻g并沒有時(shí)鐘中斷機(jī)制,會導(dǎo)致此進(jìn)程中的其它線程得不到 CPU 而持續(xù)等待。

線程實(shí)現(xiàn)在操作系統(tǒng)內(nèi)核中

內(nèi)核線程就是直接由操作系統(tǒng)內(nèi)核(Kernel)支持的線程,這種線程由內(nèi)核來完成線程切換,內(nèi)核通過操縱調(diào)度器(Scheduler)對線程進(jìn)行調(diào)度,并負(fù)責(zé)將線程的任務(wù)映射到各個處理器上。每個內(nèi)核線程可以視為內(nèi)核的一個分身,這樣操作系統(tǒng)就有能力同時(shí)處理多件事情,支持多線程的內(nèi)核就叫做多線程內(nèi)核(Multi-Threads Kernel)。

程序員直接使用操作系統(tǒng)中已經(jīng)實(shí)現(xiàn)的線程,而線程的創(chuàng)建、銷毀、調(diào)度和維護(hù),都是靠操作系統(tǒng)(準(zhǔn)確的說是內(nèi)核)來實(shí)現(xiàn),程序員只需要使用系統(tǒng)調(diào)用,而不需要自己設(shè)計(jì)線程的調(diào)度算法和線程對 CPU 資源的搶占使用。

使用用戶線程加輕量級進(jìn)程混合實(shí)現(xiàn)

在這種混合實(shí)現(xiàn)下,即存在用戶線程,也存在輕量級進(jìn)程。用戶線程還是完全建立在用戶空間中,因此用戶線程的創(chuàng)建、切換、析構(gòu)等操作依然廉價(jià),并且可以支持大規(guī)模的用戶線程并發(fā)。而操作系統(tǒng)提供支持的輕量級進(jìn)程則作為用戶線程和內(nèi)核線程之間的橋梁,這樣可以使用內(nèi)核提供的線程調(diào)度功能及處理器映射,并且用戶線程的系統(tǒng)調(diào)用要通過輕量級進(jìn)程來完成,大大降低了整個進(jìn)程被完全阻塞的風(fēng)險(xiǎn)。在這種混合模式中,用戶線程與輕量級進(jìn)程的數(shù)量比是不定的,即為 N:M 的關(guān)系:

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

Golang 的協(xié)程就是使用了這種模型,在用戶態(tài),協(xié)程能快速的切換,避免了線程調(diào)度的 CPU 開銷問題,協(xié)程相當(dāng)于線程的線程。

Linux 中的線程

在 Linux 2.4 版以前,線程的實(shí)現(xiàn)和管理方式就是完全按照進(jìn)程方式實(shí)現(xiàn)的;在 Linux 2.6 之前,內(nèi)核并不支持線程的概念,僅通過輕量級進(jìn)程(Lightweight Process)模擬線程;輕量級進(jìn)程是建立在內(nèi)核之上并由內(nèi)核支持的用戶線程,它是內(nèi)核線程的高度抽象,每一個輕量級進(jìn)程都與一個特定的內(nèi)核線程關(guān)聯(lián)。內(nèi)核線程只能由內(nèi)核管理并像普通進(jìn)程一樣被調(diào)度。這種模型大的特點(diǎn)是線程調(diào)度由內(nèi)核完成了,而其他線程操作(同步、取消)等都是核外的線程庫(Linux Thread)函數(shù)完成的。

為了完全兼容 Posix 標(biāo)準(zhǔn),Linux 2.6 首先對內(nèi)核進(jìn)行了改進(jìn),引入了線程組的概念(仍然用輕量級進(jìn)程表示線程),有了這個概念就可以將一組線程組織稱為一個進(jìn)程,不過內(nèi)核并沒有準(zhǔn)備特別的調(diào)度算法或是定義特別的數(shù)據(jù)結(jié)構(gòu)來表征線程;相反,線程僅僅被視為一個與其他進(jìn)程(概念上應(yīng)該是線程)共享某些資源的進(jìn)程(概念上應(yīng)該是線程)。在實(shí)現(xiàn)上主要的改變就是在 task_struct 中加入 tgid 字段,這個字段就是用于表示線程組 id 的字段。在用戶線程庫方面,也使用 NPTL 代替 Linux Thread,不同調(diào)度模型上仍然采用 1 對 1 模型。

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

進(jìn)程的實(shí)現(xiàn)是調(diào)用 fork 系統(tǒng)調(diào)用:pid_t fork(void);,線程的實(shí)現(xiàn)是調(diào)用 clone 系統(tǒng)調(diào)用:int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)。與標(biāo)準(zhǔn) fork() 相比,線程帶來的開銷非常小,內(nèi)核無需單獨(dú)復(fù)制進(jìn)程的內(nèi)存空間或文件描寫敘述符等等。這就節(jié)省了大量的 CPU 時(shí)間,使得線程創(chuàng)建比新進(jìn)程創(chuàng)建快上十到一百倍,能夠大量使用線程而無需太過于操心帶來的 CPU 或內(nèi)存不足。無論是 fork、vfork、kthread_create 最后都是要調(diào)用 do_fork,而 do_fork 就是根據(jù)不同的函數(shù)參數(shù),對一個進(jìn)程所需的資源進(jìn)行分配。

內(nèi)核線程

內(nèi)核線程是由內(nèi)核自己創(chuàng)建的線程,也叫做守護(hù)線程(Deamon),在終端上用命令 ps -Al 列出的所有進(jìn)程中,名字以 k 開關(guān)以 d 結(jié)尾的往往都是內(nèi)核線程,比如 kthreadd、kswapd 等。與用戶線程相比,它們都由 do_fork() 創(chuàng)建,每個線程都有獨(dú)立的 task_struct 和內(nèi)核棧;也都參與調(diào)度,內(nèi)核線程也有優(yōu)先級,會被調(diào)度器平等地?fù)Q入換出。二者的不同之處在于,內(nèi)核線程只工作在內(nèi)核態(tài)中;而用戶線程則既可以運(yùn)行在內(nèi)核態(tài)(執(zhí)行系統(tǒng)調(diào)用時(shí)),也可以運(yùn)行在用戶態(tài);內(nèi)核線程沒有用戶空間,所以對于一個內(nèi)核線程來說,它的 0~3G 的內(nèi)存空間是空白的,它的 current->mm 是空的,與內(nèi)核使用同一張頁表;而用戶線程則可以看到完整的 0~4G 內(nèi)存空間。

在 Linux 內(nèi)核啟動的最后階段,系統(tǒng)會創(chuàng)建兩個內(nèi)核線程,一個是 init,一個是 kthreadd。其中 init 線程的作用是運(yùn)行文件系統(tǒng)上的一系列”init”腳本,并啟動 shell 進(jìn)程,所以 init 線程稱得上是系統(tǒng)中所有用戶進(jìn)程的祖先,它的 pid 是 1。kthreadd 線程是內(nèi)核的守護(hù)線程,在內(nèi)核正常工作時(shí),它永遠(yuǎn)不退出,是一個死循環(huán),它的 pid 是 2。

Coroutine | 協(xié)程

協(xié)程是用戶模式下的輕量級線程,最準(zhǔn)確的名字應(yīng)該叫用戶空間線程(User Space Thread),在不同的領(lǐng)域中也有不同的叫法,譬如纖程(Fiber)、綠色線程(Green Thread)等等。操作系統(tǒng)內(nèi)核對協(xié)程一無所知,協(xié)程的調(diào)度完全有應(yīng)用程序來控制,操作系統(tǒng)不管這部分的調(diào)度;一個線程可以包含一個或多個協(xié)程,協(xié)程擁有自己的寄存器上下文和棧,協(xié)程調(diào)度切換時(shí),將寄存器上細(xì)紋和棧保存起來,在切換回來時(shí)恢復(fù)先前保運(yùn)的寄存上下文和棧。

協(xié)程的優(yōu)勢如下:

  • 節(jié)省內(nèi)存,每個線程需要分配一段棧內(nèi)存,以及內(nèi)核里的一些資源
  • 節(jié)省分配線程的開銷(創(chuàng)建和銷毀線程要各做一次 syscall)
  • 節(jié)省大量線程切換帶來的開銷
  • 與 NIO 配合實(shí)現(xiàn)非阻塞的編程,提高系統(tǒng)的吞吐

比如 Golang 里的 go 關(guān)鍵字其實(shí)就是負(fù)責(zé)開啟一個 Fiber,讓 func 邏輯跑在上面。而這一切都是發(fā)生的用戶態(tài)上,沒有發(fā)生在內(nèi)核態(tài)上,也就是說沒有 ContextSwitch 上的開銷。協(xié)程的實(shí)現(xiàn)庫中筆者較為常用的譬如 Go Routine、node-fibers、Java-Quasar 等。

Go 的協(xié)程模型

Go 線程模型屬于多對多線程模型,在操作系統(tǒng)提供的內(nèi)核線程之上,Go 搭建了一個特有的兩級線程模型。Go 中使用使用 Go 語句創(chuàng)建的 Goroutine 可以認(rèn)為是輕量級的用戶線程,Go 線程模型包含三個概念:

  • G: 表示 Goroutine,每個 Goroutine 對應(yīng)一個 G 結(jié)構(gòu)體,G 存儲 Goroutine 的運(yùn)行堆棧、狀態(tài)以及任務(wù)函數(shù),可重用。G 并非執(zhí)行體,每個 G 需要綁定到 P 才能被調(diào)度執(zhí)行。

  • P: Processor,表示邏輯處理器,對 G 來說,P 相當(dāng)于 CPU 核,G 只有綁定到 P(在 P 的 local runq 中)才能被調(diào)度。對 M 來說,P 提供了相關(guān)的執(zhí)行環(huán)境(Context),如內(nèi)存分配狀態(tài)(mcache),任務(wù)隊(duì)列(G)等,P 的數(shù)量決定了系統(tǒng)內(nèi)大可并行的 G 的數(shù)量(物理 CPU 核數(shù) >= P 的數(shù)量),P 的數(shù)量由用戶設(shè)置的 GOMAXPROCS 決定,但是不論 GOMAXPROCS 設(shè)置為多大,P 的數(shù)量大為 256。

  • M: Machine,OS 線程抽象,代表著真正執(zhí)行計(jì)算的資源,在綁定有效的 P 后,進(jìn)入 schedule 循環(huán);M 的數(shù)量是不定的,由 Go Runtime 調(diào)整,為了防止創(chuàng)建過多 OS 線程導(dǎo)致系統(tǒng)調(diào)度不過來,目前默認(rèn)大限制為 10000 個。

在 Go 中每個邏輯處理器(P)會綁定到某一個內(nèi)核線程上,每個邏輯處理器(P)內(nèi)有一個本地隊(duì)列,用來存放 Go 運(yùn)行時(shí)分配的 goroutine。多對多線程模型中是操作系統(tǒng)調(diào)度線程在物理 CPU 上運(yùn)行,在 Go 中則是 Go 的運(yùn)行時(shí)調(diào)度 Goroutine 在邏輯處理器(P)上運(yùn)行。

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

Go 的棧是動態(tài)分配大小的,隨著存儲數(shù)據(jù)的數(shù)量而增長和收縮。每個新建的 Goroutine 只有大約 4KB 的棧。每個棧只有 4KB,那么在一個 1GB 的 RAM 上,我們就可以有 256 萬個 Goroutine 了,相對于 Java 中每個線程的 1MB,這是巨大的提升。Golang 實(shí)現(xiàn)了自己的調(diào)度器,允許眾多的 Goroutines 運(yùn)行在相同的 OS 線程上。就算 Go 會運(yùn)行與內(nèi)核相同的上下文切換,但是它能夠避免切換至 ring-0 以運(yùn)行內(nèi)核,然后再切換回來,這樣就會節(jié)省大量的時(shí)間。

在 Go 中存在兩級調(diào)度:

  • 一級是操作系統(tǒng)的調(diào)度系統(tǒng),該調(diào)度系統(tǒng)調(diào)度邏輯處理器占用 cpu 時(shí)間片運(yùn)行;
  • 一級是 Go 的運(yùn)行時(shí)調(diào)度系統(tǒng),該調(diào)度系統(tǒng)調(diào)度某個 Goroutine 在邏輯處理上運(yùn)行。

使用 Go 語句創(chuàng)建一個 Goroutine 后,創(chuàng)建的 Goroutine 會被放入 Go 運(yùn)行時(shí)調(diào)度器的全局運(yùn)行隊(duì)列中,然后 Go 運(yùn)行時(shí)調(diào)度器會把全局隊(duì)列中的 Goroutine 分配給不同的邏輯處理器(P),分配的 Goroutine 會被放到邏輯處理器(P)的本地隊(duì)列中,當(dāng)本地隊(duì)列中某個 Goroutine 就緒后待分配到時(shí)間片后就可以在邏輯處理器上運(yùn)行了。

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

Java 協(xié)程的討論

目前,JVM 本身并未提供協(xié)程的實(shí)現(xiàn)庫,像 Quasar 這樣的協(xié)程框架似乎也仍非主流的并發(fā)問題解決方案,在本部分我們就討論下在 Java 中是否有必要一定要引入?yún)f(xié)程。在普通的 Web 服務(wù)器場景下,譬如 Spring Boot 中默認(rèn)的 Worker 線程池線程數(shù)在 200(50 ~ 500) 左右,如果從線程的內(nèi)存占用角度來考慮,每個線程上下文約 128KB,那么 500 個線程本身的內(nèi)存占用在 60M,相較于整個堆棧不過爾爾。而 Java 本身提供的線程池,對于線程的創(chuàng)建與銷毀都有非常好的支持;即使 Vert.x 或 Kotlin 中提供的協(xié)程,往往也是基于原生線程池實(shí)現(xiàn)的。

從線程的切換開銷的角度來看,我們常說的切換開銷往往是針對于活躍線程;而普通的 Web 服務(wù)器天然會有大量的線程因?yàn)檎埱笞x寫、DB 讀寫這樣的操作而掛起,實(shí)際只有數(shù)十個并發(fā)活躍線程會參與到 OS 的線程切換調(diào)度。而如果真的存在著大量活躍線程的場景,Java 生態(tài)圈中也存在了 Akka 這樣的 Actor 并發(fā)模型框架,它能夠感知線程何時(shí)能夠執(zhí)行工作,在用戶空間中構(gòu)建運(yùn)行時(shí)調(diào)度器,從而支持百萬級別的 Actor 并發(fā)。

實(shí)際上我們引入?yún)f(xié)程的場景,更多的是面對所謂百萬級別連接的處理,典型的就是 IM 服務(wù)器,可能需要同時(shí)處理大量空閑的鏈接。此時(shí)在 Java 生態(tài)圈中,我們可以使用 Netty 去進(jìn)行處理,其基于 NIO 與 Worker Thread 實(shí)現(xiàn)的調(diào)度機(jī)制就很類似于協(xié)程,可以解決絕大部分因?yàn)?IO 的等待造成資源浪費(fèi)的問題。而從并發(fā)模型對比的角度,如果我們希望能遵循 Go 中以消息傳遞方式實(shí)現(xiàn)內(nèi)存共享的理念,那么也可以采用 Disruptor 這樣的模型。

Java 線程與操作系統(tǒng)線程

Java 線程在 JDK1.2 之前,是基于稱為“綠色線程”(Green Threads)的用戶線程實(shí)現(xiàn)的,而到了 JDK1.2 及以后,JVM 選擇了更加穩(wěn)健且方便使用的操作系統(tǒng)原生的線程模型,通過系統(tǒng)調(diào)用,將程序的線程交給了操作系統(tǒng)內(nèi)核進(jìn)行調(diào)度。因此,在目前的 JDK 版本中,操作系統(tǒng)支持怎樣的線程模型,在很大程度上決定了 Java 虛擬機(jī)的線程是怎樣映射的,這點(diǎn)在不同的平臺上沒有辦法達(dá)成一致,虛擬機(jī)規(guī)范中也并未限定 Java 線程需要使用哪種線程模型來實(shí)現(xiàn)。線程模型只對線程的并發(fā)規(guī)模和操作成本產(chǎn)生影響,對 Java 程序的編碼和運(yùn)行過程來說,這些差異都是透明的。

對于 Sun JDK 來說,它的 Windows 版與 Linux 版都是使用一對一的線程模型實(shí)現(xiàn)的,一條 Java 線程就映射到一條輕量級進(jìn)程之中,因?yàn)?Windows 和 Linux 系統(tǒng)提供的線程模型就是一對一的。也就是說,現(xiàn)在的 Java 中線程的本質(zhì),其實(shí)就是操作系統(tǒng)中的線程,Linux 下是基于 pthread 庫實(shí)現(xiàn)的輕量級進(jìn)程,Windows 下是原生的系統(tǒng) Win32 API 提供系統(tǒng)調(diào)用從而實(shí)現(xiàn)多線程。

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

在現(xiàn)在的操作系統(tǒng)中,因?yàn)榫€程依舊被視為輕量級進(jìn)程,所以操作系統(tǒng)中線程的狀態(tài)實(shí)際上和進(jìn)程狀態(tài)是一致的模型。從實(shí)際意義上來講,操作系統(tǒng)中的線程除去 new 和 terminated 狀態(tài),一個線程真實(shí)存在的狀態(tài),只有:

  • ready:表示線程已經(jīng)被創(chuàng)建,正在等待系統(tǒng)調(diào)度分配 CPU 使用權(quán)。
  • running:表示線程獲得了 CPU 使用權(quán),正在進(jìn)行運(yùn)算。
  • waiting:表示線程等待(或者說掛起),讓出 CPU 資源給其他線程使用。

對于 Java 中的線程狀態(tài):無論是 Timed Waiting ,Waiting 還是 Blocked,對應(yīng)的都是操作系統(tǒng)線程的 waiting(等待)狀態(tài)。而 Runnable 狀態(tài),則對應(yīng)了操作系統(tǒng)中的 ready 和 running 狀態(tài)。Java 線程和操作系統(tǒng)線程,實(shí)際上同根同源,但又相差甚遠(yuǎn)。

延伸閱讀

并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程

您可以通過以下導(dǎo)航來在 Gitbook 中閱讀筆者的系列文章,涵蓋了技術(shù)資料歸納、編程語言與理論、Web 與大前端、服務(wù)端開發(fā)與基礎(chǔ)架構(gòu)、云計(jì)算與大數(shù)據(jù)、數(shù)據(jù)科學(xué)與人工智能、產(chǎn)品設(shè)計(jì)等多個領(lǐng)域:

  • 知識體系:《Awesome Lists | CS 資料集錦》、《Awesome CheatSheets | 速學(xué)速查手冊》、《Awesome Interviews | 求職面試必備》、《Awesome RoadMaps | 程序員進(jìn)階指南》、《Awesome MindMaps | 知識脈絡(luò)思維腦圖》、《Awesome-CS-Books | 開源書籍(.pdf)匯總》

  • 編程語言:《編程語言理論》、《Java 實(shí)戰(zhàn)》、《JavaScript 實(shí)戰(zhàn)》、《Go 實(shí)戰(zhàn)》、《Python 實(shí)戰(zhàn)》、《Rust 實(shí)戰(zhàn)》

  • 軟件工程、模式與架構(gòu):《編程范式與設(shè)計(jì)模式》、《數(shù)據(jù)結(jié)構(gòu)與算法》、《軟件架構(gòu)設(shè)計(jì)》、《整潔與重構(gòu)》、《研發(fā)方式與工具》

  • Web 與大前端:《現(xiàn)代 Web 開發(fā)基礎(chǔ)與工程實(shí)踐》、《數(shù)據(jù)可視化》、《iOS》、《Android》、《混合開發(fā)與跨端應(yīng)用》

  • 服務(wù)端開發(fā)實(shí)踐與工程架構(gòu):《服務(wù)端基礎(chǔ)》、《微服務(wù)與云原生》、《測試與高可用保障》、《DevOps》、《Node》、《Spring》、《信息安全與***測試》

  • 分布式基礎(chǔ)架構(gòu):《分布式系統(tǒng)》、《分布式計(jì)算》、《數(shù)據(jù)庫》、《網(wǎng)絡(luò)》、《虛擬化與編排》、《云計(jì)算與大數(shù)據(jù)》、《Linux 與操作系統(tǒng)》

  • 數(shù)據(jù)科學(xué),人工智能與深度學(xué)習(xí):《數(shù)理統(tǒng)計(jì)》、《數(shù)據(jù)分析》、《機(jī)器學(xué)習(xí)》、《深度學(xué)習(xí)》、《自然語言處理》、《工具與工程化》、《行業(yè)應(yīng)用》

  • 產(chǎn)品設(shè)計(jì)與用戶體驗(yàn):《產(chǎn)品設(shè)計(jì)》、《交互體驗(yàn)》、《項(xiàng)目管理》

  • 行業(yè)應(yīng)用:《行業(yè)迷思》、《功能域》、《電子商務(wù)》、《智能制造》

此外,你還可前往 xCompass 交互式地檢索、查找需要的文章/鏈接/書籍/課程;或者在 MATRIX 文章與代碼索引矩陣中查看文章與項(xiàng)目源代碼等更詳細(xì)的目錄導(dǎo)航信息。最后,你也可以關(guān)注微信公眾號:『某熊的技術(shù)之路』以獲取最新資訊。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

網(wǎng)站標(biāo)題:并發(fā)面試必備系列之進(jìn)程、線程與協(xié)程-創(chuàng)新互聯(lián)
地址分享:http://chinadenli.net/article24/djgpje.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動網(wǎng)站建設(shè)、營銷型網(wǎng)站建設(shè)虛擬主機(jī)網(wǎng)站排名、搜索引擎優(yōu)化、網(wǎng)站收錄

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司
亚洲熟女一区二区三四区| 成人免费视频免费观看| 欧美丝袜诱惑一区二区| 日本人妻中出在线观看| 欧美日韩国产免费看黄片| 国产日韩在线一二三区| 五月综合激情婷婷丁香| 欧美一区二区三区视频区| 免费大片黄在线观看国语| 亚洲欧美日本国产不卡| 不卡中文字幕在线免费看| 国产免费人成视频尤物| 国产大屁股喷水在线观看视频| 亚洲中文字幕熟女丝袜久久| 国产日韩欧美在线亚洲| 亚洲欧美一二区日韩高清在线| 欧美国产极品一区二区| 五月婷婷亚洲综合一区| 日本女优一色一伦一区二区三区 | 国产精品十八禁亚洲黄污免费观看| 欧美日韩一区二区午夜| 欧美日韩国产自拍亚洲| 国产一级精品色特级色国产| 国内精品伊人久久久av高清| 夜色福利久久精品福利| 国产日韩欧美国产欧美日韩 | 老司机精品一区二区三区| 亚洲精品成人午夜久久| 好吊日成人免费视频公开| 丰满少妇被猛烈撞击在线视频| 高清一区二区三区大伊香蕉| 欧美人妻盗摄日韩偷拍| 亚洲最新一区二区三区| 欧美亚洲国产日韩一区二区| 中国一区二区三区人妻| 日韩高清中文字幕亚洲| 精品少妇人妻av一区二区蜜桃| 亚洲国产欧美精品久久| 九九视频通过这里有精品| 91欧美日韩精品在线| 国产精品香蕉在线的人|