多個go協程從乙個channel獲取資料,需要額外的排程嗎?

時間 2021-10-18 07:20:12

1樓:Aka-Kamicoding

go內部最常見的設計模式:使用通訊的方式進行資訊的共享,而不是用共享記憶體的方式

Goroutine之間的通訊方式:Channel

有兩種方式進行執行緒之間的通訊:

共享記憶體(全域性變數)

需要通過鎖機制來解決競態問題

限制同一時間使用該共享記憶體的執行緒數量

訊息機制

Go中實現了CSP模型(Communication sequential processes)

Goroutine、Channel分別對應了實體和媒介

先進先出:

多channel時,接受資訊、傳送資訊的順序與操作channel的順序保持一致

無鎖管道:

樂觀鎖與悲觀鎖

是一種併發控制思想

悲觀鎖:對於資料的操作都會帶上鎖,防止在此期間被修改

資料庫寫操作

樂觀鎖:只有資料提交時,才採用CAS的方式進行提交以及解衝突

資料庫MVC併發讀取

鎖機制在休眠與喚醒帶來的額外上下文切換代價會降低效率,目前針對三種不同的情況做出了不同的優化

同步channel,緩衝區共享資料無關,直接將資料傳送給接收方

非同步channel,基於環形緩衝區,使用傳統生產者、消費者模型,還是需要鎖機制

chan struct{}宣告的channel,不占用記憶體空間,無需實現

type hchan struct

type waitq struct

ep表示當前Goroutine的channel操作的變數物件指標,send中為傳送的變數,recv中為接收的變數

根據緩衝區的情況,分為三種分配方式:

預設:分別為hchan以及其緩衝區分配記憶體

無緩衝區:只為hchan分配記憶體空間

有緩衝區、且儲存的不是指標型別:為hchan、緩衝區分配記憶體,且1處於同一段連續的記憶體空間

最後會統一更新elemsize、elemtype、dataqsiz的值

傳送的時候先上鎖,防止多執行緒併發修改

檢測channel是否關閉,如果已經關閉,panic

呼叫chansend

存在等待的接收者時,直接傳送給阻塞的接收者

將資料拷貝到接收變數對應的位址上

標記接收Goroutine為可執行的

緩衝區存在空餘空間的時候,寫入緩衝區

計算下乙個儲存的資料的位置

呼叫typedmemmove將資料拷貝到緩衝區

增加sendx、qcount計數器

不存在緩衝區時、緩衝區已滿時,當前goroutine阻塞等待其他接受goroutine接收資料

獲取當前傳送資料時用的Goroutine

構建阻塞佇列中的最小元素,內部資訊包括當前的channel、傳送的資料的位址

加入傳送阻塞佇列

當前goroutine陷入沉睡

實際上除了關閉的情況(向關閉的channel傳送訊息會panic),其他的情況是對稱的

有兩種特殊情況:

channel為空,相當於使當前Goroutine陷入沉睡,且永遠不會被喚醒(不會有其他的Goroutine向該channel傳送訊息)

當前channel關閉,且緩衝區沒有資料的時候,會清除ep指標中資料並且立刻返回

正常的接受情況也分為幾種不同的型別:

緩衝區已滿、無緩衝區,存在傳送阻塞佇列

無緩衝區

將傳送佇列中的Goroutine的儲存的elem拷貝到接收Goroutine對應變數的位址

緩衝區已滿

實際上就是乙個替換的過程

將原來recv指向的元素拷貝到接收Goroutine對應變數的位址,recv指標遞增

傳送佇列頭的Goroutine中的元素,代替原recv指標位置元素

從緩衝區接收資料

緩衝區為空、無緩衝區且傳送隊列為空

將當前Goroutine包裝成sudog,放入接收阻塞佇列

當channel已經關閉或者為空指標都會panic

將所有的接收佇列以及傳送佇列中的Goroutine清除,並且放到Goroutine ready中

2樓:

測試一下就知道了:

package

main

import

("fmt"

"time"

)func

main())

exit

:=make

(chan

struct

{})fori:=

0;i<

nThreads;i

++}}()}

t0:=

time

.Now()n

:=100

*10000

fori:=0

;i

i++{}}

fmt.

Printf

("%10d %v\n"

,nThreads

,time

.Since(t0

)/time

.Duration(n

))close

(exit)}

}執行結果:

reus@reus-work-pc ~> ./a100 540ns

1000 682ns

10000 775ns

100000 788ns

1000000 762ns

reus@reus-work-pc ~> ./a100 531ns

1000 672ns

10000 776ns

100000 791ns

1000000 760ns

reus@reus-work-pc ~> ./a100 537ns

1000 688ns

10000 773ns

100000 785ns

1000000 766ns

reus@reus-work-pc ~> ./a100 544ns

1000 686ns

10000 772ns

100000 790ns

1000000 761ns

可見 goroutine 的數量,是會產生影響的,但從 100 個 gouroutine 到 100 萬個 goroutine,也只是從 500ns 到 700ns。

所以不需要手工排程,交給執行時排程即可。

如何從乙個男孩變成乙個男人?

鹽選推薦 如果父母身邊有一些這樣的網路,有值得信任的成年人,不管是單獨的個人,還是有組織的集體,我們都可以把孩子交給他們,讓孩子找到自我價值和歸屬感。男孩到了一定的年齡後,他們的視野已經超越了家庭。15 歲左右,他們已經開始向著未來前進了 但是必須要有目標,並且要有人來扶持和引導。這就意味著需要構建...

如何從乙個瘦宅成為乙個肥宅?

革聲 不出門,不運動。外賣泡麵快樂水。吃飽睡,睡飽吃。堅持兩個月你就會發現 肉肉都跑過來了,身體也不行了 肥什麼宅啊,生活健康嘛好不好。 歸海雁 胖瘦真的是個人體質問題,有的人喝涼水都長胖,有的人天生腸胃不好,怎麼吃都不胖。想要增胖攝入高糖和高脂肪的食物當然有效,但是個人有過血淋淋的經驗,心情也對我...

怎麼從乙個星際二白痴變成乙個高手?

毛八兩 放戰術這個遊戲最重要的是想象力,如果只是打基本功那麼毫無意義,我曾經用野影刀打死乙個鑽石z,說明戰術可以在實力懸殊的情況下獲勝。這是非常重要的,因為這種乙個人的遊戲,如果一局都不贏就很難有動力打下去。另外,狗也是一種本事,如果你打五盤能打出五種戰術,比到練基本功更有意思。另外,基本功還是要有...