最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言CSP并發(fā)模型goroutine及channel底層實(shí)現(xiàn)原理

 更新時(shí)間:2022年05月25日 16:43:49   作者:正則化  
這篇文章主要為大家介紹了Go語言CSP并發(fā)模型goroutine?channel底層實(shí)現(xiàn)原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

參考Go的CSP并發(fā)模型實(shí)現(xiàn):M, P, G

Go語言是為并發(fā)而生的語言,Go語言是為數(shù)不多的在語言層面實(shí)現(xiàn)并發(fā)的語言。

并發(fā)(concurrency):多個(gè)任務(wù)在同一段時(shí)間內(nèi)運(yùn)行。

并行(parallellism):多個(gè)任務(wù)在同一時(shí)刻運(yùn)行。

Go的CSP并發(fā)模型(goroutine + channel)

Go實(shí)現(xiàn)了兩種并發(fā)形式。

  • 多線程共享內(nèi)存:Java或者C++等語言中的多線程開發(fā)。
  • CSP(communicating sequential processes)并發(fā)模型:Go語言特有且推薦使用的。

不同于傳統(tǒng)的多線程通過共享內(nèi)存來通信,CSP講究的是“以通信的方式來共享內(nèi)存”。

普通的線程并發(fā)模型,就是像Java、C++、或者Python,他們線程間通信都是通過共享內(nèi)存的方式來進(jìn)行的。非常典型的方式就是,在訪問共享數(shù)據(jù)(例如數(shù)組、Map、或者某個(gè)結(jié)構(gòu)體或?qū)ο螅┑臅r(shí)候,通過鎖來訪問,因此,在很多時(shí)候,衍生出一種方便操作的數(shù)據(jù)結(jié)構(gòu),叫做“線程安全的數(shù)據(jù)結(jié)構(gòu)”。

Go的CSP并發(fā)模型,是通過goroutine和channel來實(shí)現(xiàn)的。

  • goroutine 是Go語言中并發(fā)的執(zhí)行單位??梢岳斫鉃橛脩艨臻g的線程。
  • channel是Go語言中不同goroutine之間的通信機(jī)制,即各個(gè)goroutine之間通信的”管道“,有點(diǎn)類似于Linux中的管道。

1、goroutine

Go語言最大的特色就是從語言層面支持并發(fā)(goroutine),goroutine是Go中最基本的執(zhí)行單元。事實(shí)上每一個(gè)Go程序至少有一個(gè)goroutine:主goroutine。當(dāng)程序啟動(dòng)時(shí),它會自動(dòng)創(chuàng)建。我們在使用Go語言進(jìn)行開發(fā)時(shí),一般會使用goroutine來處理并發(fā)任務(wù)。

goroutine機(jī)制有點(diǎn)像線程池:

go 內(nèi)部有三個(gè)對象: P(processor) 代表上下文(M所需要的上下文環(huán)境,也就是處理用戶級代碼邏輯的處理器),M(work thread)代表內(nèi)核線程,G(goroutine)協(xié)程。

正常情況下一個(gè)cpu核運(yùn)行一個(gè)內(nèi)核線程,一個(gè)內(nèi)核線程運(yùn)行一個(gè)goroutine協(xié)程。當(dāng)一個(gè)goroutine阻塞時(shí),會啟動(dòng)一個(gè)新的內(nèi)核線程來運(yùn)行其他goroutine,以充分利用cpu資源。所以線程往往會比cpu核數(shù)更多。

example

在單核情況下,所有g(shù)oroutine運(yùn)行在同一個(gè)內(nèi)核線程(M0)中,每一個(gè)內(nèi)核線程維護(hù)一個(gè)上下文(P),任何時(shí)刻,一個(gè)上下文中只有一個(gè)goroutine,其他goroutine在runqueue中等待。一個(gè)goroutine運(yùn)行完自己的時(shí)間片后,讓出上下文,自己回到runqueue中。如下圖左邊所示,只有一個(gè)G0在運(yùn)行,而其他goroutine都掛起了。

當(dāng)正在運(yùn)行的G0阻塞的時(shí)候(IO之類的),會再創(chuàng)建一個(gè)新的內(nèi)核線程(M1),P轉(zhuǎn)到新的內(nèi)核線程中去運(yùn)行。

當(dāng)M0返回時(shí)(不再阻塞),它會嘗試從其他線程中“偷”一個(gè)上下文(cpu)過來,如果沒有偷到,會把goroutine放到global runqueue中去,然后把自己放入線程緩存中。上下文會定時(shí)檢查global runqueue切換goroutine運(yùn)行。

goroutine的優(yōu)點(diǎn):

1、創(chuàng)建與銷毀的開銷小

線程創(chuàng)建時(shí)需要向操作系統(tǒng)申請資源,并且在銷毀時(shí)將資源歸還,因此它的創(chuàng)建和銷毀的開銷比較大。相比之下,goroutine的創(chuàng)建和銷毀是由go語言在運(yùn)行時(shí)自己管理的,因此開銷更低。所以一個(gè)Golang的程序中可以支持10w級別的Goroutine。每個(gè) goroutine (協(xié)程) 默認(rèn)占用內(nèi)存遠(yuǎn)比 Java 、C 的線程少(*goroutine:*2KB ,線程:8MB)

2、切換開銷小

這是goroutine于線程的主要區(qū)別,也是golang能夠?qū)崿F(xiàn)高并發(fā)的主要原因。

線程的調(diào)度方式是搶占式的,如果一個(gè)線程的執(zhí)行時(shí)間超過了分配給它的時(shí)間片,就會被其它可執(zhí)行的線程搶占。在線程切換的過程中需要保存/恢復(fù)所有的寄存器信息,比如16個(gè)通用寄存器,PC(Program Counter),SP(Stack Pointer),段寄存器等等。

而goroutine的調(diào)度是協(xié)同式的,沒有時(shí)間片的概念,由Golang完成,它不會直接地與操作系統(tǒng)內(nèi)核打交道。當(dāng)goroutine進(jìn)行切換的時(shí)候,之后很少量的寄存器需要保存和恢復(fù)(PC和SP)。因此gouroutine的切換效率更高。

總的來說,操作系統(tǒng)的一個(gè)線程下可以并發(fā)執(zhí)行上千個(gè)goroutine,每個(gè)goroutine所占用的資源和切換開銷都很小,因此,goroutine是golang適合高并發(fā)場景的重要原因。

生成一個(gè)goroutine的方法十分簡單,直接使用go關(guān)鍵字即可:

go func();

2、channel

參考由淺入深剖析 go channel

channel的使用方法:聲明之后,傳數(shù)據(jù)用channel <- data,取數(shù)據(jù)用<-channel。channel分為無緩沖和有緩沖,無緩沖會同步阻塞,即每次生產(chǎn)消息都會阻塞到消費(fèi)者將消息消費(fèi);有緩沖的不會立刻阻塞。

無緩存channel

ch := make(chan int)
// write to channel
ch <- x
// read from channel
x <- ch
// another way to read
x = <- ch

從無緩存的 channel 中讀取消息會阻塞,直到有 goroutine 向該 channel 中發(fā)送消息;同理,向無緩存的 channel 中發(fā)送消息也會阻塞,直到有 goroutine 從 channel 中讀取消息。

example

c := make(chan int)  // Allocate a channel.
// Start the sort in a goroutine; when it completes, signal on the channel.
go func() {
    list.Sort()
    c <- 1  // Send a signal; value does not matter.
}()
doSomethingForAWhile()
<-c

主goroutine定義一個(gè)無緩存的channel,然后開啟一個(gè)新的goroutine執(zhí)行排序任務(wù),接著主goroutine繼續(xù)向下執(zhí)行doSomethingForAWhile,接著要從channel中取值,但是channel是空的,因此主goroutine阻塞。等到新goroutine排序完畢,向channel中寫值后,主goroutine從channel中取到值,然后才能繼續(xù)向下執(zhí)行。

有緩存channel

有緩存的 channel 的聲明方式為指定 make 函數(shù)的第二個(gè)參數(shù),該參數(shù)為 channel 緩存的容量

ch := make(chan int, 10)

當(dāng)緩存未滿時(shí),向 channel 中發(fā)送消息時(shí)不會阻塞,當(dāng)緩存滿時(shí),發(fā)送操作將被阻塞,直到有其他 goroutine 從中讀取消息

ch := make(chan int, 3)
// blocked, read from empty buffered channel
<- ch

相應(yīng)的,當(dāng) channel 中消息不為空時(shí),讀取消息不會出現(xiàn)阻塞,當(dāng) channel 為空時(shí),讀取操作會造成阻塞,直到有 goroutine 向 channel 中寫入消息。

ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
// blocked, send to full buffered channel
ch <- 4

通過 len 函數(shù)可以獲得 chan 中的元素個(gè)數(shù),通過 cap 函數(shù)可以得到 channel 的緩存長度。

channel 也可以使用 range 取值,并且會一直從 channel 中讀取數(shù)據(jù),直到有 goroutine 對改 channel 執(zhí)行 close 操作,循環(huán)才會結(jié)束。

// consumer worker
ch := make(chan int, 10)
for x := range ch{
    fmt.Println(x)
}

等價(jià)于

for {
    x, ok := <- ch
    if !ok {
        break
    }
    fmt.Println(x)
}

3、Go并發(fā)模型的底層實(shí)現(xiàn)原理

參考Golang CSP并發(fā)模型

無論在語言層面用的是何種并發(fā)模型,到了操作系統(tǒng)層面,一定是以線程的形態(tài)存在的。而操作系統(tǒng)根據(jù)資源訪問權(quán)限的不同,體系架構(gòu)可分為用戶空間和內(nèi)核空間。

  • 內(nèi)核空間主要操作訪問CPU資源、I/O資源、內(nèi)存資源等硬件資源,為上層應(yīng)用程序提供最基本的基礎(chǔ)資源。
  • 用戶空間就是上層應(yīng)用程序的固定活動(dòng)空間,用戶空間不可以直接訪問資源,必須通過“系統(tǒng)調(diào)用”、“庫函數(shù)”或“Shell腳本”來調(diào)用內(nèi)核空間提供的資源。

golang使用goroutine做為最小的執(zhí)行單位,但是這個(gè)執(zhí)行單位還是在用戶空間,實(shí)際上最后被處理器執(zhí)行的還是內(nèi)核中的線程,用戶線程和內(nèi)核線程的調(diào)度方法有:

  • 1:1,即一個(gè)內(nèi)核線程對應(yīng)一個(gè)用戶級線程(并發(fā)度低,浪費(fèi)cpu資源,上下文切換需要消耗額外的資源)。
  • 1:N,即一個(gè)內(nèi)核線程對應(yīng)N個(gè)用戶級線程(并發(fā)度高,但是只用一個(gè)內(nèi)核線程,不能有效利用多核CPU)。
  • M:N,即M個(gè)內(nèi)核線程對應(yīng)N個(gè)用戶級線程(上述兩種方式的折中,缺點(diǎn)是線程調(diào)度會復(fù)雜一些)

golang 通過為goroutine提供語言層面的調(diào)度器,來實(shí)現(xiàn)了高效率的M:N線程對應(yīng)關(guān)系

M:是內(nèi)核線程

P : 是調(diào)度協(xié)調(diào),用于協(xié)調(diào)M和G的執(zhí)行,內(nèi)核線程只有拿到了 P才能對goroutine繼續(xù)調(diào)度執(zhí)行,一般都是通過限定P的個(gè)數(shù)來控制golang的并發(fā)度

G : 是待執(zhí)行的goroutine,包含這個(gè)goroutine的棧空間

Gn : 灰色背景的Gn 是已經(jīng)掛起的goroutine,它們被添加到了執(zhí)行隊(duì)列中,然后需要等待網(wǎng)絡(luò)IO的goroutine,當(dāng)P通過 epoll查詢到特定的fd的時(shí)候,會重新調(diào)度起對應(yīng)的,正在掛起的goroutine。

Golang為了調(diào)度的公平性,在調(diào)度器加入了steal working 算法 ,在一個(gè)P自己的執(zhí)行隊(duì)列,處理完之后,它會先到全局的執(zhí)行隊(duì)列中偷G進(jìn)行處理,如果沒有的話,再會到其他P的執(zhí)行隊(duì)列中搶G來進(jìn)行處理。

4、一個(gè)CSP例子

參考golang中的CSP并發(fā)模型

生產(chǎn)者-消費(fèi)者Sample:

package main
import (
   "fmt" 
   "time"
)
// 生產(chǎn)者
func Producer (queue chan<- int){
        for i:= 0; i < 10; i++ {
                queue <- i
        }
}
// 消費(fèi)者
func Consumer( queue <-chan int){
        for i :=0; i < 10; i++{
                v := <- queue
                fmt.Println("receive:", v)
        }
}
func main(){
        queue := make(chan int, 1)
        go Producer(queue)
        go Consumer(queue)
        time.Sleep(1e9) //讓Producer與Consumer完成
}

生產(chǎn)者goroutine往channel傳值,消費(fèi)者goroutine往channel取值,這兩個(gè)goroutine通過channel完成通信。

以上就是Go語言CSP并發(fā)模型goroutine channel底層實(shí)現(xiàn)原理的詳細(xì)內(nèi)容,更多關(guān)于go CSP并發(fā)模型goroutine channel的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go語言開發(fā)中如何優(yōu)雅得關(guān)閉協(xié)程方法

    go語言開發(fā)中如何優(yōu)雅得關(guān)閉協(xié)程方法

    這篇文章主要為大家介紹了go語言開發(fā)中如何優(yōu)雅得關(guān)閉協(xié)程方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • 一文帶你掌握Go語言并發(fā)模式中的Context的上下文管理

    一文帶你掌握Go語言并發(fā)模式中的Context的上下文管理

    在?Go?的日常開發(fā)中,Context?上下文對象無處不在,無論是處理網(wǎng)絡(luò)請求、數(shù)據(jù)庫操作還是調(diào)用?RPC?等場景,那你真的熟悉它的正確用法嗎,隨著本文一探究竟吧
    2023-05-05
  • 入門學(xué)習(xí)Go的基本語法

    入門學(xué)習(xí)Go的基本語法

    這篇文章主要介紹了Go語法的基本概念,本文講解了Golang的基本知識、基礎(chǔ)語法、相關(guān)術(shù)語等,需要的朋友可以參考下,希望能幫助到你
    2021-07-07
  • 詳解Go函數(shù)和方法之間有什么區(qū)別

    詳解Go函數(shù)和方法之間有什么區(qū)別

    這篇文章就簡單和大家聊一聊在Go中函數(shù)與方法之間的區(qū)別,文章通過代碼示例介紹的非常詳細(xì),對我們的學(xué)習(xí)或工作有一定的幫助,感興趣的小伙伴跟著小編一起來看看吧
    2023-07-07
  • Golang中如何對MySQL進(jìn)行操作詳解

    Golang中如何對MySQL進(jìn)行操作詳解

    這篇文章主要給大家介紹了關(guān)于在Golang中如何對MySQL進(jìn)行操作的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用Golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Go?io/fs.FileMode文件系統(tǒng)基本操作和權(quán)限管理深入理解

    Go?io/fs.FileMode文件系統(tǒng)基本操作和權(quán)限管理深入理解

    這篇文章主要為大家介紹了Go?io/fs.FileMode文件系統(tǒng)基本操作和權(quán)限管理深入理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • golang協(xié)程關(guān)閉踩坑實(shí)戰(zhàn)記錄

    golang協(xié)程關(guān)閉踩坑實(shí)戰(zhàn)記錄

    協(xié)程(coroutine)是Go語言中的輕量級線程實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于golang協(xié)程關(guān)閉踩坑的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • Golang中下劃線(_)的不錯(cuò)用法分享

    Golang中下劃線(_)的不錯(cuò)用法分享

    golang中的下劃線表示忽略變量的意思,也沒有產(chǎn)生新的變量,但是后面的表達(dá)式依然會被執(zhí)行,本文為大家整理了golang中下劃線的一些不錯(cuò)的用法,需要的可以參考下
    2023-05-05
  • Golang并發(fā)發(fā)送HTTP請求的各種方法

    Golang并發(fā)發(fā)送HTTP請求的各種方法

    在 Golang 領(lǐng)域,并發(fā)發(fā)送 HTTP 請求是優(yōu)化 Web 應(yīng)用程序的一項(xiàng)重要技能,本文探討了實(shí)現(xiàn)此目的的各種方法,從基本的 goroutine 到涉及通道和sync.WaitGroup 的高級技術(shù),需要的朋友可以參考下
    2024-02-02
  • 在Golang中使用iota案例詳解

    在Golang中使用iota案例詳解

    在Go語言中,iota是一個(gè)預(yù)定義的標(biāo)識符,用于在常量聲明中生成連續(xù)的遞增值,iota的值從0開始,每次在常量聲明中使用時(shí)遞增,本就給大家講解一下Golang中iota的使用案例,感興趣的同學(xué)跟著小編一起來看看吧
    2023-07-07

最新評論

慈溪市| 台东县| 满城县| 克什克腾旗| 沿河| 竹北市| 江口县| 奉新县| 黑河市| 万州区| 梅河口市| 乐昌市| 隆化县| 临朐县| 三原县| 新平| 呼和浩特市| 开江县| 新郑市| 渝中区| 葫芦岛市| 无锡市| 大厂| 武邑县| 永昌县| 故城县| 开阳县| 巩义市| 塔城市| 衡东县| 左云县| 横峰县| 福州市| 滦平县| 东莞市| 宝坻区| 璧山县| 时尚| 谷城县| 合阳县| 禄劝|