溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

golang中線程和協(xié)程有哪些區(qū)別

發(fā)布時(shí)間:2021-03-19 09:10:25 來源:億速云 閱讀:252 作者:小新 欄目:編程語言

這篇文章主要介紹golang中線程和協(xié)程有哪些區(qū)別,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

區(qū)別:線程中數(shù)據(jù)存儲(chǔ)在內(nèi)核態(tài)的內(nèi)存空間;而協(xié)程中數(shù)據(jù)存儲(chǔ)在線程提供的用戶態(tài)內(nèi)存空間。線程的任務(wù)調(diào)度由內(nèi)核實(shí)現(xiàn),搶占方式,依賴各種鎖;協(xié)程的任務(wù)調(diào)度由用戶態(tài)實(shí)現(xiàn)的具體調(diào)度器進(jìn)行。

協(xié)程
協(xié)程,英文名Coroutine。但在 Go 語言中,協(xié)程的英文名是:gorutine。它常常被用于進(jìn)行多任務(wù),即并發(fā)作業(yè)。沒錯(cuò),就是多線程作業(yè)的那個(gè)作業(yè)。

雖然在 Go 中,我們不用直接編寫線程之類的代碼來進(jìn)行并發(fā),但是 Go 的協(xié)程卻依賴于線程來進(jìn)行。

下面我們來看看它們的區(qū)別。

線程的基礎(chǔ)介紹,這里請自行網(wǎng)上搜索文章,因?yàn)殛P(guān)于線程的優(yōu)秀介紹文章已經(jīng)很多。

協(xié)程的特點(diǎn)
這里先直接列出線程的特點(diǎn),然后從例子中進(jìn)行解析。

  • 多個(gè)協(xié)程可由一個(gè)或多個(gè)線程管理,協(xié)程的調(diào)度發(fā)生在其所在的線程中。

  • 可以被調(diào)度,調(diào)度策略由應(yīng)用層代碼定義,即可被高度自定義實(shí)現(xiàn)。

  • 執(zhí)行效率高。

  • 占用內(nèi)存少。

上面第 1第 2點(diǎn)

我們來看一個(gè)例子:
func TestGorutine(t *testing.T) {
	runtime.GOMAXPROCS(1)  // 指定最大 P 為 1,從而管理協(xié)程最多的線程為 1 個(gè)
	wg := sync.WaitGroup{} // 控制等待所有協(xié)程都執(zhí)行完再退出程序
	wg.Add(2)
	// 運(yùn)行一個(gè)協(xié)程
	go func() {
		fmt.Println(1)
		fmt.Println(2)
		fmt.Println(3)
		wg.Done()
	}()

	// 運(yùn)行第二個(gè)協(xié)程
	go func() {
		fmt.Println(65)
		fmt.Println(66)
		// 設(shè)置個(gè)睡眠,讓該協(xié)程執(zhí)行超時(shí)而被掛起,引起超時(shí)調(diào)度
		time.Sleep(time.Second)
		fmt.Println(67)
		wg.Done()
	}()
	wg.Wait()}

上面的代碼片段跑了兩個(gè)協(xié)程,運(yùn)行后,觀察輸出的順序是交錯(cuò)的??赡苁牵?/p>

656612367

意味著在執(zhí)行協(xié)程A的過程中,可以隨時(shí)中斷,去執(zhí)協(xié)程行B,協(xié)程B也可能在執(zhí)行過程中中斷再去執(zhí)行協(xié)程A。
看起來協(xié)程A 和 協(xié)程B 的運(yùn)行像是線程的切換,但是請注意,這里的 A 和 B都運(yùn)行在同一個(gè)線程里面。它們的調(diào)度不是線程的切換,而是純應(yīng)用態(tài)的協(xié)程調(diào)度。
關(guān)于上述代碼中,為什么要指定下面兩行代碼?

runtime.GOMAXPROCS(1)time.Sleep(time.Second)

這需要您去看下 Go 的協(xié)程調(diào)度入門基礎(chǔ),請看我之前的另外一篇調(diào)度分析文章:
Go 的協(xié)程調(diào)度機(jī)制

如果不設(shè)置 runtime.GOMAXPROCS(1),那么程序?qū)?huì)根據(jù)操作系統(tǒng)的 CPU 核數(shù)而啟動(dòng)對應(yīng)數(shù)量的 P,導(dǎo)致多個(gè) M,即線程的啟動(dòng)。那么我們程序中的協(xié)程,就會(huì)被分配到不同的線程里面去了。為了演示,故設(shè)置數(shù)量 1,使得它們都被分配到了同一個(gè)線程里面,存于線程的協(xié)程隊(duì)列里面,等待被執(zhí)行或調(diào)度。

協(xié)程特點(diǎn)中的第 3第 4點(diǎn)。
3. 執(zhí)行效率高。
4. 占用內(nèi)存少。

因?yàn)?mark>協(xié)程的調(diào)度切換不是線程切換,而是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數(shù)量越多,協(xié)程的性能優(yōu)勢就越明顯。調(diào)度發(fā)生在應(yīng)用態(tài)而非內(nèi)核態(tài)。

內(nèi)存的花銷,使用其所在的線程的內(nèi)存,意味著線程的內(nèi)存可以供多個(gè)協(xié)程使用。

其次協(xié)程的調(diào)度不需要多線程的鎖機(jī)制,因?yàn)橹挥幸粋€(gè)線程,也不存在同時(shí)寫變量沖突,所以執(zhí)行效率比多線程高很多。

協(xié)程和線程的整體對比

比較的點(diǎn)線程協(xié)程
數(shù)據(jù)存儲(chǔ)內(nèi)核態(tài)的內(nèi)存空間一般是線程提供的用戶態(tài)內(nèi)存空間
切換操作操作最終在內(nèi)核層完成,應(yīng)用層需要調(diào)用內(nèi)核層提供的 syscall 底層函數(shù)應(yīng)用層使用代碼進(jìn)行簡單的現(xiàn)場保存和恢復(fù)即可
任務(wù)調(diào)度由內(nèi)核實(shí)現(xiàn),搶占方式,依賴各種鎖由用戶態(tài)的實(shí)現(xiàn)的具體調(diào)度器進(jìn)行。例如 go 協(xié)程的調(diào)度器
語音支持程度絕大部分編程語言部分語言:Lua,Go,Python …
實(shí)現(xiàn)規(guī)范按照現(xiàn)代操作系統(tǒng)規(guī)范實(shí)現(xiàn)無統(tǒng)一規(guī)范。在應(yīng)用層由開發(fā)者實(shí)現(xiàn),高度自定義,比如只支持單線程的線程。不同的調(diào)度策略,等等

以上是“golang中線程和協(xié)程有哪些區(qū)別”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI