日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

Hello,大家好,又見面了!上一遍我們將 channel 相關基礎以及使用場景。這一篇,還需要再次進階理解channel 阻塞問題。以下創建一個chan類型為int,cap 為3。

ch := make(chan string,1)

channel 內部其實是一個環形buf數據結構,是一種滑動窗口機制,當make完后,就分配在 Heap 上。

Channel 是如何發送數據和接收數據,會有什么問題出現,面試也是常見。

設 G1 為發送者:

ch <- "hello"

上面,向 chan 發送一條“hello”數據:

  • 第一步: acquire lock
  • 第二步:enqueue(把“hello”拷貝buf數組里)
  • 第三步:release lock

如果 G1 發送數據超過指定cap時,會出現什么情況?

看下面實例:

ch := make(chan int,1)
ch <- 100
ch <- 200

以上會出現什么,chan 緩沖區允許大小為1,如果再往chan仍數據,滿了就會被阻塞,那么是如何實現阻塞的呢?當 chan 滿時,會進入 gopark,此時 G1 進入一個 waiting 狀態,然后會創建一個 sudog 對象,其實就sendq隊列,把 200放進去。等 buf 不滿的時候,再喚醒放入buf里面。

通過如下源碼,你會更加清晰:

type hchan struct {
  //省略部分代碼。。。
  recvq    waitq  // list of recv waiters
  sendq    waitq  // list of send waiters
  //省略部分代碼。。。
}
type waitq struct {
  first *sudog
  last  *sudog
}
type sudog struct {
  g *g
  next *sudog
  prev *sudog
  elem unsafe.Pointer // data element (may point to stack)
  acquiretime int64
  releasetime int64
  ticket      uint32
  isSelect bool
  success bool
  parent   *sudog // semaRoot binary tree
  waitlink *sudog // g.waiting list or semaRoot
  waittail *sudog // semaRoot
  c        *hchan // channel
}

設 G2 為接收者:

d := <- ch

上面,從 chan 獲取數據:

  • 第一步:也是先獲取鎖
  • 第二步:從 buf 數據里面拷貝,賦給 d 變量
  • 第三步:release lock

Go 語言核心思想:“Do not communicate by sharing memory; instead, share memory by communicating.” 你可以看看這本書名叫:Effective Go

如果接收者,接收一個空對象,也會發生什么情況?

代碼示例

ch := make(chan int,1)
t := <- ch

也會報錯如下:

fatal error: all goroutines are asleep - deadlock!

上面,從 chan 取出數據,可是沒有數據了。此時,它會把 接收者 G2 阻塞掉,也是和G1發送者一樣,也會執行 gopark 將狀態改為 waiting,不一樣的點就是。

正常情況下,接收者G2作為取出數據是去 buf 讀取數據的,但現在,buf 為空了,此時,接收者G2會將sudog導出來,因為現在G2已經被阻塞了嘛,會把G2給G,然后將t := <-ch中變量 t 是在棧上的地址,放進去elem,也就是說,只存它的地址指針在sudog里面。

最后,ch <- 200 當G1往 chan 添加200這個數據,正常情況是將數據添加到buf里面,然后喚醒 G2 是吧,而現在是將 G1 的添加200數據直接干到剛才G2阻塞的t這里變量里面。

你會認為,這樣真的可以嗎?想一想,G2 本來就是已經阻塞了,然后我們直接這么干肯定沒有什么毛病,而且效率提高了,不需要再次放入buf再取出,這個過程也是需要時間。不然,不得往chan添加數據需要加鎖、拷貝、解鎖一序列操作,那肯定就慢了,我想Go語言是為了高效及內存使用率的考慮這樣設計的。(注意,一般都是在runtime里面完成,不然會出現象安全問題。)

總結

chan 類型的特點:chan 如果為空,receiver 接收數據的時候就會阻塞等待,直到 chan 被關閉或者有新的數據到來。有這種個機制,就可以實現 wait/notify 的設計模式。

使用 channel 要思考的問題?

  • 如果N個發送者發送到chan及N個接收者,這樣會頻繁導致鎖頻繁爭用;
  • 如果N個往 chan 發送,而 buf很小,會導致 Goroutine 不斷被gopark,然后runtime開銷就大了;

相關面試題:

  • channel 有緩沖區和無緩沖區別?
  • channel 線程安全嗎?
  • 是否了解 channel 底層實現,比如channel 底層數據結構?環形buf

分享到:
標簽:語言
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定