文字解說(shuō)Golang Goroutine和線程的區(qū)別
Golang Goroutine和線程的區(qū)別 Golang,輕松學(xué)習(xí)
一、Golang Goroutine?
當(dāng)使用者分配足夠多的任務(wù),系統(tǒng)能自動(dòng)幫助使用者把任務(wù)分配到 CPU 上,讓這些任務(wù)盡量并發(fā)運(yùn)作。這種機(jī)制在 Go語(yǔ)言中被稱為 goroutine。
goroutine 是 Go語(yǔ)言中的輕量級(jí)線程實(shí)現(xiàn),由 Go 運(yùn)行時(shí)(runtime)管理。Go 程序會(huì)智能地將 goroutine 中的任務(wù)合理地分配給每個(gè) CPU。
使用每一個(gè) go 關(guān)鍵字將會(huì)額外開啟一個(gè)新的協(xié)程 goroutine
二、線程是什么?
線程(英語(yǔ):thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。一條線程指的是進(jìn)程中一個(gè)單一順序的控制流,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程,每條線程并行執(zhí)行不同的任務(wù)。
三、調(diào)度的區(qū)別
1.線程調(diào)度
線程是系統(tǒng)調(diào)度的基本單位,線程作為調(diào)度與分配的基本單位,線程切換,僅需保存和設(shè)置少量寄存器的內(nèi)容,開銷遠(yuǎn)小于進(jìn)程開銷。但這種線程切換仍然需要一個(gè)完整的上下文切換:即保存一個(gè)線程的狀態(tài)到內(nèi)存,再恢復(fù)另外一個(gè)線程的狀態(tài),最后更新調(diào)度器的數(shù)據(jù)結(jié)構(gòu)。某種意義上,這種操作還是很慢的。
2.goroutine 調(diào)度
Go運(yùn)行的時(shí)候包涵一個(gè)自己的調(diào)度器,這個(gè)調(diào)度器使用一個(gè)稱為一個(gè)M:N調(diào)度技術(shù),m個(gè)goroutine到n個(gè)os線程(可以用GOMAXPROCS來(lái)控制n的數(shù)量),Go的調(diào)度器不是由硬件時(shí)鐘來(lái)定期觸發(fā)的,而是由特定的go語(yǔ)言結(jié)構(gòu)來(lái)觸發(fā)的,他不需要切換到內(nèi)核語(yǔ)境,所以調(diào)度一個(gè)goroutine比調(diào)度一個(gè)線程的成本低很多。
Goroutine協(xié)程是一種協(xié)作任務(wù)控制機(jī)制,Goroutine可以理解為一種Go語(yǔ)言的協(xié)程。同時(shí)它可以運(yùn)行在一個(gè)或多個(gè)線程上。而Goroutine協(xié)程的切換一般由程序員在代碼中顯式控制。它避免了上下文切換的額外耗費(fèi),兼顧了多線程的優(yōu)點(diǎn),簡(jiǎn)化了高并發(fā)程序的復(fù)雜。
四、??臻g的區(qū)別
1.線程占用
每個(gè)OS的線程都有一個(gè)固定大小的棧內(nèi)存,通常是2MB,棧內(nèi)存用于保存在其他函數(shù)調(diào)用期間哪些正在執(zhí)行或者臨時(shí)暫停的函數(shù)的局部變量。這個(gè)固定的棧大小,如果對(duì)于goroutine來(lái)說(shuō),可能是一種巨大的浪費(fèi)。
以 64位環(huán)境的 JVM 為例,會(huì)默認(rèn)固定為每個(gè)線程分配 1MB ??臻g,如果大小分配不當(dāng),便會(huì)出現(xiàn)棧溢出的問(wèn)題。
2.goroutine 占用
- goroutine 所占用的內(nèi)存,均在棧中進(jìn)行管理 - goroutine 所占用的??臻g大小,由 runtime 按需進(jìn)行分配 goroutine在生命周期開始只有一個(gè)很小的棧,典型情況是2KB, 在go程序中,一次創(chuàng)建十萬(wàn)左右的goroutine也不罕見(2KB*100,000=200MB)。而且goroutine的棧不是固定大小,它可以按需增大和縮小,最大限制可以到1GB。 goroutine 相較于線程更加輕量,關(guān)鍵點(diǎn)就在于棧空間的動(dòng)態(tài)分配,這樣便可以最大限度的利用內(nèi)存資源。
五、標(biāo)識(shí)的區(qū)別
1.線程標(biāo)識(shí)
在大部分支持多線程的操作系統(tǒng)和編程語(yǔ)言中,線程有一個(gè)獨(dú)特的標(biāo)識(shí),通常是一個(gè)整數(shù)或者指針,這個(gè)特性可以讓我們構(gòu)建一個(gè)線程的局部存儲(chǔ),本質(zhì)是一個(gè)全局的map,以線程的標(biāo)識(shí)作為鍵,這樣每個(gè)線程可以獨(dú)立使用這個(gè)map存儲(chǔ)和獲取值,不受其他線程干擾。
2.goroutine 標(biāo)識(shí)
goroutine中沒有可供程序員訪問(wèn)的標(biāo)識(shí),原因是一種純函數(shù)的理念,不希望濫用線程局部存儲(chǔ)導(dǎo)致一個(gè)不健康的超距作用,即函數(shù)的行為不僅取決于它的參數(shù),還取決于運(yùn)行它的線程標(biāo)識(shí)。
總結(jié)
Golang 通過(guò)復(fù)雜的協(xié)程操作來(lái)實(shí)現(xiàn)我們的并發(fā)需求,golang是用戶線程與系統(tǒng)線程的對(duì)應(yīng)關(guān)系是多對(duì)多,既能利用多核cpu資源,也能盡可能減少上下文切換成本,代價(jià)是go需要實(shí)現(xiàn)復(fù)雜的goroutine調(diào)度機(jī)制。
相比于N:1時(shí)所有用戶線程對(duì)應(yīng)1個(gè)系統(tǒng)線程,無(wú)法利用多核cpu;1:1時(shí)1個(gè)用戶線程對(duì)應(yīng)一個(gè)系統(tǒng)線程,上下文切換成本高。通過(guò)復(fù)雜的調(diào)度實(shí)現(xiàn)N:N時(shí),即能利用多核cpu資源,也能盡可能減少上下文切換成本,成為Go語(yǔ)言最為人知的特點(diǎn),天生支持高并發(fā)與高效。
到此這篇關(guān)于Golang Goroutine和線程的區(qū)別的文章就介紹到這了,更多相關(guān)Golang Goroutine和線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
gin解析json格式的數(shù)據(jù)出錯(cuò)的處理方案
這篇文章主要介紹了gin解析json格式的數(shù)據(jù)出錯(cuò)的處理方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03Go語(yǔ)言實(shí)現(xiàn)的最簡(jiǎn)單數(shù)獨(dú)解法
前面給大家介紹過(guò)使用javascript實(shí)現(xiàn)的簡(jiǎn)單的數(shù)獨(dú)解法,小伙伴們都非常喜歡,今天我們?cè)賮?lái)分享一則go語(yǔ)言實(shí)現(xiàn)的簡(jiǎn)單的數(shù)獨(dú)解法,有需要的小伙伴來(lái)參考下。2015-03-03Go中的格式化字符串fmt.Sprintf()和fmt.Printf()使用示例
這篇文章主要為大家介紹了Go中的格式化字符串fmt.Sprintf()和fmt.Printf()使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Go語(yǔ)言通過(guò)反射實(shí)現(xiàn)獲取各種類型變量的值
反射是程序在運(yùn)行期間獲取變量的類型和值、或者執(zhí)行變量的方法的能力,這篇文章主要為大家講講Go語(yǔ)言通過(guò)反射獲取各種類型變量值的方法,需要的可以參考下2023-07-07淺談go-restful框架的使用和實(shí)現(xiàn)
這篇文章主要介紹了淺談go-restful框架的使用和實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03