溫馨提示×

溫馨提示×

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

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

GO并發(fā)編程使用方法是什么

發(fā)布時間:2023-02-24 11:39:56 來源:億速云 閱讀:127 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹了GO并發(fā)編程使用方法是什么的相關(guān)知識,內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇GO并發(fā)編程使用方法是什么文章都會有所收獲,下面我們一起來看看吧。

啥是并發(fā)編程呢

指在一臺處理器上同時處理多個任務(wù)

此處說的同時,可不是同一個時間一起手拉手做同一件事情

并發(fā)是在同一實(shí)體上的多個事件,而這個事件在同一時間間隔發(fā)生的,同一個時間段,有多個任務(wù)執(zhí)行,可是同一個時間點(diǎn),只有一個任務(wù)在執(zhí)行

為啥要有并發(fā)編程

隨著互聯(lián)網(wǎng)的普及,互聯(lián)網(wǎng)用戶人數(shù)原來越多,這對系統(tǒng)的性能帶來了巨大的挑戰(zhàn)。

我們要通過各種方式來高效利用硬件的性能(壓榨),從而提高系統(tǒng)的性能進(jìn)而提升用戶體驗(yàn),提升團(tuán)隊(duì)或者企業(yè)的競爭力。

并發(fā)是為了解決什么問題?目的是啥?

充分的利用好處理器的每一個核,以達(dá)到最高的處理性能,盡可能的運(yùn)用好每一塊磚

可是由于現(xiàn)在我們使用的CPU,內(nèi)存,IO三者之間速度不盡相同

我們?yōu)榱颂岣呦到y(tǒng)性能,計(jì)算機(jī)系統(tǒng)會將這三者速度進(jìn)行平衡,以達(dá)到最優(yōu)的效果,都有如下措施:

  • 操作系統(tǒng)增加了進(jìn)程、線程,以分時復(fù)用 CPU,進(jìn)而均衡 CPUI/O 設(shè)備的速度差異;

  • CPU 增加了緩存,以均衡與內(nèi)存的速度差異;

  • 編譯程序優(yōu)化指令執(zhí)行次序,使得緩存能夠得到更加合理地利用。

說到進(jìn)程和線程,他們都是干啥的呢,咱們順帶說一下?

進(jìn)程是程序在操作系統(tǒng)中的一次執(zhí)行過程

是 系統(tǒng)進(jìn)行資源分配和調(diào)度的一個獨(dú)立單位

線程是進(jìn)程的一個執(zhí)行實(shí)體

是 CPU 調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位。

一個進(jìn)程可以創(chuàng)建和撤銷多個線程, 并且同一個進(jìn)程中的多個線程之間可以并發(fā)執(zhí)行。

講到并發(fā)編程不得不說并發(fā)和并行有啥區(qū)別?是不是總是有小伙伴弄不清楚他們到底是啥區(qū)別,好像一樣,又好像不一樣

并發(fā)和并行的區(qū)別

一言蔽之,區(qū)別如下:

并發(fā)

多線程程序在一個核的 CPU 上運(yùn)行

并行

多線程程序在多個核的 CPU 上運(yùn)行

并發(fā)就像多個小伙伴跑接力,同一個時間點(diǎn)只會有一個小伙伴在跑,互相有影響

GO并發(fā)編程使用方法是什么

并行就像是多個小伙伴同一個起點(diǎn)一起跑,互不干擾

GO并發(fā)編程使用方法是什么

我們需要記住一點(diǎn),再強(qiáng)調(diào)一波:

并發(fā)不是并行

并發(fā)主要由切換時間片來實(shí)現(xiàn)"同時"運(yùn)行

并行則是直接利用多核實(shí)現(xiàn)多線程的運(yùn)行,

在 GO 可以設(shè)置使用核數(shù),以發(fā)揮多核計(jì)算機(jī)的能力,不過設(shè)置核數(shù)都是依賴于硬件的

那么,講到GO的并發(fā)編程,就必須上我們的主角,那就是協(xié)程

協(xié)程 goroutine 是啥

協(xié)程是一種程序組件

是由子例程(過程、函數(shù)、例程、方法、子程序)的概念泛化而來的

子例程只有一個入口點(diǎn)且只返回一次,而協(xié)程允許多個入口點(diǎn),可以在指定位置掛起和恢復(fù)執(zhí)行。

協(xié)程和線程分別有啥特點(diǎn)嘞

協(xié)程

獨(dú)立的棧空間,共享堆空間,調(diào)度由用戶自己控制

本質(zhì)上有點(diǎn)類似于用戶級線程,這些用戶級線程的調(diào)度也是自己實(shí)現(xiàn)的。

線程

一個線程上可以跑多個協(xié)程,協(xié)程是輕量級的線程。

GO 高并發(fā)的原因是啥

  • goroutine 奉行通過通信來共享內(nèi)存

  • 每個一個GO的實(shí)例有4~5KB的棧內(nèi)存占用,并且由于 GO 實(shí)現(xiàn)機(jī)制而大幅減少的創(chuàng)建和銷毀開銷

  • Golang 在語言層面上就支持協(xié)程 goroutine

GOLANG并發(fā)編程涉及哪些知識點(diǎn)呢

  • 基本協(xié)程的原理,實(shí)現(xiàn)方式,雖然說,GO中使用協(xié)程很方便,可以我們必須要知其然而值其所以然

  • Goroutine 池

  • runtime 包的使用

  • Channel 通道

  • 定時器

  • 并發(fā)且安全的鎖

  • 原子操作

  • select 多路復(fù)用

  • 等等...

Goroutine的那些事

我們寫C/C++的時候,我們必然也是要實(shí)現(xiàn)并發(fā)編程

我們通常需要自己維護(hù)一個線程池,并且需要自己去包裝一個又一個的任務(wù),同時需要自己去調(diào)度線程執(zhí)行任務(wù)并維護(hù)上下文切換

且做線程池的時候,我們需要自己做一個線程管理的角色,靈活動態(tài)壓縮和擴(kuò)容

可是能不能有這樣一種機(jī)制,我們只需要定義多個任務(wù),讓系統(tǒng)去幫助我們把這些任務(wù)分配到CPU上實(shí)現(xiàn)并發(fā)執(zhí)行

GO里面就正好有這樣的機(jī)制

goroutine 的概念類似于線程

goroutine 是由Go的運(yùn)行時(runtime)調(diào)度和管理的

Go程序會智能地將 goroutine 中的任務(wù)合理地分配給每個CPU

Go 在語言層面已經(jīng)內(nèi)置了調(diào)度和上下文切換的機(jī)制

寫 GO 比較爽的一個地方是:

在GO里面,你不需要去自己寫進(jìn)程、線程、協(xié)程

我們可以使用 goroutine 包

如何使用 goroutine

我們需要讓某個任務(wù)并發(fā)執(zhí)行的時候,只需要把這個任務(wù)包裝成一個函數(shù)

專門開啟一個 goroutine 協(xié)程 去執(zhí)行這個函數(shù)就可以了 , GO一個協(xié)程,很方便

一個 goroutine 必定對應(yīng)一個函數(shù),可以創(chuàng)建多個 goroutine 去執(zhí)行相同的函數(shù),只是多個協(xié)程都是做同一個事情罷了

我們先來使用一下協(xié)程,再來拋磚引玉,適當(dāng)?shù)姆窒硪幌?/p>

啟動單個協(xié)程

func Hi() {
    fmt.Println("this is Hi Goroutine!")
}
func main() {
    Hi()
    fmt.Println("main goroutine!")
}

我們一般調(diào)用函數(shù)是如上這個樣子的,效果如下

this is Hi Goroutine!
main goroutine!

其實(shí)我們調(diào)用協(xié)程的話,也與上述類似

我們可以使用 go 后面加上函數(shù)名字,來開辟一個協(xié)程,專門做函數(shù)需要執(zhí)行的事情

func main() {
    go Hi() // 啟動一個goroutine 協(xié)程 去執(zhí)行 Hi 函數(shù)
    fmt.Println("main goroutine!")

實(shí)際效果我們可以看到,程序只打印了 main goroutine!

main goroutine!

在程序啟動的時候,Go 程序就會為 main() 函數(shù)創(chuàng)建一個默認(rèn)的 goroutine 協(xié)程

當(dāng) main() 函數(shù)返回的時候,剛開辟的另外一個 goroutine 協(xié)程 就結(jié)束了

所有在 main() 函數(shù)中啟動的 goroutine 協(xié)程 會一同結(jié)束,老大死了,其余的傀儡也灰飛煙滅了

我們也可以讓主協(xié)程等等一定子協(xié)程,待子協(xié)程處理完自己的事情,退出后,主協(xié)程再自己退出,這和我們寫C/C++進(jìn)程 和 線程的時候,類似

簡單的,我們可以使用 time.sleep 函數(shù)來讓主協(xié)程阻塞等待

我們也可以使用 上述提到的 使用 select{} 來達(dá)到目的

當(dāng)然也有其他的方式,后續(xù)文章會慢慢的分享到

多個協(xié)程

那么多個協(xié)程又是怎么玩的呢?

我們使用 sync.WaitGroup 來實(shí)現(xiàn)goroutine 協(xié)程的同步

package main

import (
	"fmt"
	"sync"
)

var myWg sync.WaitGroup

func Hi(i int) {
	// goroutine 協(xié)程 結(jié)束就 記錄 -1
	defer myWg.Done()
	fmt.Println("Hello Goroutine! the ", i)
}
func main() {

	for i := 0; i < 10; i++ {
		// 啟動一個goroutine 協(xié)程 就記錄 +1
		myWg.Add(1)
		go Hi(i)
	}

	// 等待所有記錄 的goroutine 協(xié)程 都結(jié)束
	myWg.Wait() 
}

會有如下輸出,每一個協(xié)程打印的數(shù)字并不是按照順序來的:

Hello Goroutine! the  9
Hello Goroutine! the  4
Hello Goroutine! the  2
Hello Goroutine! the  3
Hello Goroutine! the  6
Hello Goroutine! the  5
Hello Goroutine! the  7
Hello Goroutine! the  8
Hello Goroutine! the  1
Hello Goroutine! the  0

還是同樣的, 如果是主協(xié)程先退出,那么子協(xié)程還行繼續(xù)運(yùn)行嗎?

毋庸置疑,主協(xié)程退出,子協(xié)程也會跟著退出

GO 中的協(xié)程

分享如下幾個點(diǎn)

GO中的棧是可增長的

一般都有固定的棧內(nèi)存(通常為2MB),goroutine 的棧不是固定的,goroutine 的棧大小可以擴(kuò)展到1GB

goroutine 是如何調(diào)度

這就不得不提 GPM

GPM是Go語言運(yùn)行時(runtime)層面實(shí)現(xiàn)的,我們先簡單了解一下GPM分別代表啥

G

就是個 goroutine ,里面除了存放本 goroutine 信息外 還有與所在P的綁定等信息

P

Processor 管理著一組 goroutine 隊(duì)列

P 里面會存儲當(dāng)前 goroutine 運(yùn)行的上下文環(huán)境(函數(shù)指針,堆棧地址及地址邊界)

P 會對自己管理的 goroutine 隊(duì)列做一些調(diào)度(比如把占用CPU時間較長的 goroutine 暫停、運(yùn)行后續(xù)的 goroutine)

當(dāng)自己的隊(duì)列消費(fèi)完了就去全局隊(duì)列里取,如果全局隊(duì)列里也消費(fèi)完了會去其他P的隊(duì)列里搶任務(wù)。

M(machine)

是 Go 運(yùn)行時(runtime)對操作系統(tǒng)內(nèi)核線程的虛擬

M 與內(nèi)核線程一般是一一映射的關(guān)系, 一個 groutine 最終是要放到 M上執(zhí)行

這里的 P 與 M 一般也是一一對應(yīng)的

P 管理著一組G 掛載在 M 上運(yùn)行

當(dāng)一個 G 長久阻塞在一個 M 上時,runtime 會新建一個M,

阻塞 G 所在的 P 會把其他的 G 掛載在新建的M上

這個時候,當(dāng)舊的 G 阻塞完成或者認(rèn)為其已經(jīng)掛了的話,就會回收舊的 M

還有一點(diǎn)

P 的個數(shù)是通過 runtime.GOMAXPROCS 設(shè)定(最大256),這個數(shù)字也依賴于自己的硬件,在并發(fā)量大的時候會增加一些 P 和 M ,但不會太多。

關(guān)于“GO并發(fā)編程使用方法是什么”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“GO并發(fā)編程使用方法是什么”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(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)容。

go
AI