国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

講透Go中的并發接收控制結構Select

開發 后端
在switch語句中,會逐個匹配case語句(可以是值也可以是表達式),一個一個的判斷過去,直到有符合的語句存在,執行匹配的語句內容后跳出switch。

[[413689]]

select 與 switch

讓我們來復習一下switch語句,在switch語句中,會逐個匹配case語句(可以是值也可以是表達式),一個一個的判斷過去,直到有符合的語句存在,執行匹配的語句內容后跳出switch。

  1. func demo(number int){ 
  2.     switch{ 
  3.         case number >= 90: 
  4.         fmt.Println("優秀"
  5.         default
  6.         fmt.Println("太搓了"
  7.     } 

而 select 用于處理通道,它的語法與 switch 非常類似。每個 case 語句里必須是一個 channel 操作。它既可以用于 channel 的數據接收,也可以用于 channel 的數據發送。

  1. func foo() { 
  2.  chanInt := make(chan int
  3.  defer close(chanInt) 
  4.  go func() { 
  5.   select { 
  6.   case data, ok := <-chanInt: 
  7.    if ok { 
  8.     fmt.Println(data) 
  9.    } 
  10.   default
  11.    fmt.Println("全部阻塞"
  12.   } 
  13.  }() 
  14.  chanInt <- 1 

輸出1

  • 這是一個簡單的接收發送模型
  • 如果 select 的多個分支都滿足條件,則會隨機的選取其中一個滿足條件的分支。
  • 第 6 行加上 ok 是因為上一節講過,如果不加會導致通道關閉時收到零值
  • 回憶之前的知識,讓接收和發送在不同的goroutine里,否則會死鎖

這個程序存在什么問題?

假如發送太慢,所有case都處于阻塞狀態,會直接執行default的內容。這里加一行sleep試試。

  1. func bar() { 
  2.  chanInt := make(chan int
  3.  defer close(chanInt) 
  4.  go func() { 
  5.   .... 
  6.  }() 
  7.  time.Sleep(time.Second
  8.  chanInt <- 1 
  • 倒數第二行加了sleep 1 秒,導致select語句提前結束
  • 猜測一下會輸出全部阻塞嗎?
  1. 全部阻塞 
  2. fatal error: all goroutines are asleep - deadlock! 
  3.  
  4. goroutine 1 [chan send]: 
  5. main.bar() 

是會輸出全部阻塞的。

因為接收執行完了,退出了goroutine,而發送才剛剛執行到,沒有與其匹配的接收,故死鎖。

正確的做法是把接收套在循環里面。

  1. func baz() { 
  2.  chanInt := make(chan int
  3.  defer close(chanInt) 
  4.  go func() { 
  5.   for { 
  6.    select { 
  7.        ... 
  8.    } 
  9.   } 
  10.  }() 
  11.  chanInt <- 1 
  • 不再死鎖了
  • 假如程序不停止,會出現一個泄露的goroutine,永遠的在for循環中無法跳出,此時引入下一節的內容

通知機制

Go 語言總是簡單和靈活的,雖然沒有針對提供專門的機制來處理退出,但我們可以自己組合

  1. func main() { 
  2.  chanInt, done := make(chan int), make(chan struct{}) 
  3.  defer close(chanInt) 
  4.  defer close(done) 
  5.  go func() { 
  6.   for { 
  7.    select { 
  8.    case <-chanInt: 
  9.    case <-done: 
  10.     break 
  11.    } 
  12.   } 
  13.  }() 
  14.  done <- struct{}{} 

沒有給chanInt發送任何東西,按理說會阻塞,導致goroutine泄露

但可以使用額外的通道完成協程的退出控制

這種方式還可以做到周期性處理任務,下一節我們再詳細講解

case 的并發性

case是有并發屬性的,比如兩次輸入,分別等待 1、2 秒,再進行兩次讀取,會花 3 秒時間嗎?

  1. func main() { 
  2.  c1,c2 := make(chan string), make(chan string) 
  3.     close(c1) 
  4.     close(c2) 
  5.  go func() { 
  6.   time.Sleep(time.Second * 1) 
  7.   c1 <- "one" 
  8.  }() 
  9.  go func() { 
  10.   time.Sleep(time.Second * 2) 
  11.   c2 <- "two" 
  12.  }() 
  13.  start := time.Now() // 獲取當前時間 
  14.  for i := 0; i < 2; i++ { 
  15.   select { 
  16.   case <-c1: 
  17.   case <-c2: 
  18.   } 
  19.  } 
  20.  elapsed := time.Since(start) 
  21.  // 這里沒有用到3秒,為什么? 
  22.  fmt.Println("該函數執行完成耗時:", elapsed) 

以上代碼先初始化兩個 channel c1 和 c2,然后開啟兩個 goroutine 分別往 c1 和 c2 寫入數據,再通過 select 監聽兩個 channel,從中讀取數據并輸出。

運行結果如下:

  1. $ go run channel.go 
  2. received one 
  3. received two 
  4. 該函數執行完成耗時:2.004695535s 

這充分說明case是并發的,但要注意此處的并發是 case 對channel阻塞做出的特殊處理。

case并發的原理

假如case后左邊和右邊跟了函數,會執行函數,我們來探索一下。

定義A、B函數,作用相同

  1. func A() int { 
  2.  fmt.Println("start A"
  3.  time.Sleep(1 * time.Second
  4.  fmt.Println("end A"
  5.  return 1 

定義函數lee,請問該函數執行完成耗時多少呢?

  1. func lee() { 
  2.  ch, done := make(chan int), make(chan struct{}) 
  3.  defer close(ch) 
  4.  go func() { 
  5.   select { 
  6.   case ch <- A(): 
  7.   case ch <- B(): 
  8.   case <-done: 
  9.   } 
  10.  }() 
  11.  done <- struct{}{} 

答案是 2 秒

  1. start A 
  2. end A 
  3. start B 
  4. end B 
  5. main.leespend time: 2.003504395s 
  • select 掃描是從左到右從上到下的,按這個順序先求值,如果是函數會先執行函數。
  • 然后立馬判斷是否可以立即執行(這里是指 case 是否會因為執行而阻塞)。
  • 所以兩個函數都會進入,而且是先進入 A 再進入 B,兩個函數都會執行完,所以等待時間會累計。

如果都不會阻塞,此時就會使用一個偽隨機的算法,去選中一個 case,只要選中了其他就被放棄了。

超時控制

我們來模擬一個更真實點的例子,讓程序一段時間超時退出。

定義一個結構體

  1. type Worker struct { 
  2.  stream  <-chan int //處理 
  3.  timeout time.Duration //超時 
  4.  done    chan struct{} //結束信號 

定義初始化函數

  1. func NewWorker(stream <-chan int, timeout int) *Worker { 
  2.  return &Worker{ 
  3.   stream:  stream, 
  4.   timeout: time.Duration(timeout) * time.Second
  5.   done:    make(chan struct{}), 
  6.  } 

定義超時處理函數

  1. func (w *Worker) afterTimeStop() { 
  2.  go func() { 
  3.   time.Sleep(w.timeout) 
  4.   w.done <- struct{}{} 
  5.  }() 
  • 超過時間發送結束信號

接收數據并處理函數

  1. func (w *Worker) Start() { 
  2.  w.afterTimeStop() 
  3.  for { 
  4.   select { 
  5.   case data, ok := <-w.stream: 
  6.    if !ok { 
  7.     return 
  8.    } 
  9.    fmt.Println(data) 
  10.   case <-w.done: 
  11.    close(w.done) 
  12.    return 
  13.   } 
  14.  } 
  • 收到結束信號關閉函數
  • 這樣的方法就可以讓程序在等待 1 秒后繼續執行,而不會因為 ch 讀取等待而導致程序停滯。
  1. func main() { 
  2.  stream := make(chan int
  3.  defer close(stream) 
  4.  
  5.  w := NewWorker(stream, 3) 
  6.  w.Start() 

實際 3 秒到程序運行結束。

這種方式巧妙地實現了超時處理機制,這種方法不僅簡單,在實際項目開發中也是非常實用的。

小結

本節介紹了select的用法以及包含的陷阱,我們學會了

  • case是并發的
  • case只針對通道傳輸阻塞做特殊處理,如果有計算將會先進行計算
  • 掃描是從左到右從上到下的,按這個順序先求值,如果是函數會先執行函數。如果函數運行時間長,時間會累計
  • 在case全部阻塞時,會執行default中的內容
  • 可使用結束信號,讓select退出
  • 延時發送結束信號可以實現超時自動退出的功能

問題:為什么w.stream沒有程序向他發送數據,卻沒有死鎖呢?

本節源碼位置 https://github.com/golang-minibear2333/golang/blob/master/4.concurrent/4.5-select”

本文轉載自微信公眾號「機智的程序員小熊」,可以通過以下二維碼關注。轉載本文請聯系機智的程序員小熊公眾號。

 

責任編輯:武曉燕 來源: 機智的程序員小熊
相關推薦

2024-01-08 13:40:00

并發安全? 數量

2024-06-17 08:40:16

2025-01-13 12:00:00

反射Java開發

2023-09-15 11:32:18

selectGo可視化解釋

2025-05-22 09:01:28

2023-01-30 15:41:10

Channel控制并發

2025-08-04 02:45:00

反轉IoC編程

2025-06-03 02:00:00

2023-12-20 07:30:54

Goselect編程

2020-03-26 09:18:54

高薪本質因素

2020-05-20 09:55:42

Git底層數據

2020-05-07 08:07:57

synchronize線程

2017-11-06 17:16:55

Linux設備驅動并發控制

2009-02-09 10:06:03

并發控制Web應用悲觀鎖

2025-10-30 00:55:00

AIAgent分布式

2020-01-14 11:17:33

Go并發Linux

2010-07-13 13:56:43

Perl foreac

2024-09-06 12:52:59

2020-03-12 09:02:34

數據思維統計學大數據

2021-04-07 06:00:18

JavaScript 前端并發控制
點贊
收藏

51CTO技術棧公眾號

欧美大片拔萝卜| 91影视免费在线观看| av在线免费一区| 欧美在线视频全部完| 在线小视频网址| 一本一道波多野结衣一区二区| 午夜黄色一级片| 亚洲人成在线观看一区二区| 淫视频在线观看| 一区二区三区不卡视频在线观看| 成年免费网站| 91国产丝袜在线播放| 国产私人尤物无码不卡| 亚洲成人午夜电影| av男人的天堂在线| 91精品国产一区二区三区蜜臀| 欧美久久天堂| 亚洲人成网站777色婷婷| 午夜av不卡| 亚洲最大在线视频| 91福利精品在线观看| 久久久免费精品| 国产一区二区三区不卡视频网站| 国产精品日韩一区| 丝袜脚交一区二区| 久久香蕉视频网站| av电影在线观看完整版一区二区| 国产91在线免费| 国产精品久久久久久久久免费樱桃| 日本a级片免费| 亚洲午夜久久久久久久久电影网 | 亚洲一二三区不卡| 三级做a全过程在线观看| 在线观看一区二区视频| 免费黄色网址在线观看| 日韩成人免费视频| 国产999精品在线观看| 91成人理论电影| 激情综合色丁香一区二区| 777av视频| 一区二区三区**美女毛片| 天堂影院在线| 色悠悠国产精品| 精品国产一区二区三区小蝌蚪 | 久久美女福利视频| 26uuu国产在线精品一区二区| 免费男女羞羞的视频网站中文版| 日韩欧美国产一区二区| 四虎影视成人| 久久久噜噜噜久久中文字免| 台湾色综合娱乐中文网| 日本成人黄色| 91美女在线视频| 四虎亚洲成人| 555www成人网| 国产一区二区在线免费观看| 九色福利视频| www亚洲欧美| 国产精品豆花视频| 中文字幕免费中文| 精品国产一区二区亚洲人成毛片| 欧美一性一交| 91动漫在线看| 91国产福利在线| 尤物tv在线精品| 在线视频一区观看| 在线观看亚洲一区| 久久天堂久久| 久久日韩精品| 日本乱人伦一区| 中文字幕久久精品一区二区| 正在播放国产精品| 亚洲一区二区三区中文字幕| 精品国产鲁一鲁****| 欧美日韩精品久久久免费观看| caoporn国产精品| 国内老司机av在线| 国产免费成人av| 亚洲欧美偷拍另类a∨色屁股| 蜜桃在线视频| 久久综合九色综合久99| 国产精品丝袜91| 国产精品一区hongkong| 国产精品二区二区三区| 国产精品久久一级| **爰片久久毛片| 已婚少妇美妙人妻系列| 最新国产成人av网站网址麻豆| 久久精品99国产国产精| 色网在线观看| 久久综合九色欧美狠狠| 欧美三级乱人伦电影| 三区四区电影在线观看| 成人网18免费软件大全| 国产日本欧美在线观看| 日韩亚洲欧美在线| 免费在线视频一区| 日本一区二区三区在线不卡| 日本中文字幕在线看| 成人欧美一区二区三区在线| 久久综合久久鬼色中文字| 欧美videossex另类| 欧美亚洲国产免费| 亚洲成人av一区二区三区| 亚州综合一区| 国产无套内射久久久国产| 精品国产一区a| 蜜臀久久久99精品久久久久久| 视频在线精品一区| 欧美日韩国产一级片| 国产色99精品9i| 黄色小视频大全| 日韩电影在线一区二区| 亚洲一级黄色片| 欧美精品一区二区三区一线天视频 | 欧美精品日韩三级| 一区二区欧美国产| 国产精品成人网| 污片在线观看一区二区| av综合在线播放| 欧美在线电影| 中文字幕一区久| jizz蜜桃视频在线观看| 日韩成人三级视频| 久久久神马电影| 成人做爽爽免费视频| 26uuu另类亚洲欧美日本老年| 欧美黄色www| 国产不卡在线观看| 国产成人亚洲综合91精品| 国产91色在线免费| 欧美精品videofree1080p| 久久久噜久噜久久综合| 日本亚洲欧美成人| 日韩免费精品视频| 日韩有码在线观看| 日本老师69xxx| 99久久国产免费免费| 美女亚洲精品| 大荫蒂性生交片| 1pon在线| 免费不卡视频| 男人的天堂在线视频免费观看| 伦理片一区二区三区| 中日韩一区二区三区| av超碰在线观看| 成人高清免费在线播放| 影音先锋电影在线观看| 伊人影院在线视频| 99久久婷婷国产综合精品首页| 亚洲二区av| 欧美理论电影大全| 久久不射中文字幕| 久久久不卡网国产精品二区| 一二三四社区欧美黄| 欧美xxxxx牲另类人与| 日韩视频永久免费观看| 国产成人亚洲综合91精品| 蜜桃传媒视频麻豆一区 | 日本黄色免费在线| 狠狠一区二区三区| 欧美日韩久久| 成人免费视频免费观看| 性做久久久久久| 国产又粗又猛又爽又黄91精品| 亚洲激情校园春色| 亚洲高清在线观看| 成人女保姆的销魂服务| 国产香蕉一区二区三区| 蜜桃视频在线观看视频| 三上悠亚亚洲一区| 在线电影一区二区| 国产日韩欧美一区二区三区乱码| 欧美亚洲一区三区| 欧美激情伊人电影| 国产专区在线视频| 三级理论午夜在线观看| 久蕉在线视频| 视频免费在线看| 丁香花高清视频完整版在线观看| 久久久久久久激情| 欧美牲交a欧美牲交aⅴ免费真 | av免费播放| 日本超碰在线观看| 91国内在线| 成人勉费视频| 欧美第一在线视频| 在线亚洲免费| 26uuu精品一区二区在线观看| 亚洲不卡在线观看| 91成人天堂久久成人| 久久综合久久网| 小水嫩精品福利视频导航| 欧美啪啪免费视频| 欧美激情一级欧美精品| 成人午夜黄色影院| 日韩av片在线看| av网址在线看| h网站久久久| 日产精品一区|