浅谈Go Channel 高级实践
channel æ¯ golang éç¸å½æ趣çä¸ä¸ªåè½ï¼å¨æä½¿ç¨ golang ç¼ç çç»éªéï¼å¤§é¨åäºä»¶é½ä¼æ¯å¨äº«å channel å goroutine éåçä¹è¶£ãæ以æ¬æ主è¦ä»ç» channel çä¸äºæ趣çç¨æ³ã
è¿éæ Oling Cat ç¿»è¯çGoç¼ç¨è¯è¨è§èéå³äº channelï¼ä¿¡éï¼çæè¿°ï¼
ä¿¡éæä¾äºä¸ç§æºå¶ï¼å®å¨ä¸¤ä¸ªå¹¶åæ§è¡çå½æ°ä¹é´è¿è¡åæ¥ï¼å¹¶éè¿ä¼ éï¼ä¸è¯¥ä¿¡éåç´ ç±»åç¸ç¬¦çï¼å¼æ¥è¿è¡éä¿¡ã
è¿ä¸ªä¸ªæè¿°åä¹å³ãåæ¯ç¥ãå¨æ第ä¸æ¬¡é读çæ¶åï¼å®å¨ä¸æç½è¿å°åºæ¯ä¸ªä»ä¹ç©æãäºå®ä¸ï¼å¯ä»¥è®¤ä¸º channel æ¯ä¸ä¸ªç®¡éæèåè¿ååºéåï¼é常ç®åä¸è½»éãchannel 并ä¸æ¯ Golang é¦åçãå®åæ ·ä½ä¸ºåç½®åè½åºç°å¨å¶ä»è¯è¨ä¸ãå¨å¤§å¤æ°æåµä¸ï¼å®æ¯ä¸ä¸ªå大ãå笨ãåå¤æçæ¶æ¯éåç³»ç»çä¸ä¸ªåè½ã
æ¬æ主è¦è®²å®è·µï¼åçé¨åä¼ä¸ç¬å¸¦è¿ï¼å³äº go è¯è¨å¹¶åå®ç°ååå模ååç»ä¼ææç« ã
channel å®ç°çæºç ä¸å¤æï¼æ¨èé读ï¼https://github.com/golang/go/blob/master/src/runtime/chan.go
channel æ¯å¹²ä»ä¹ç
æä¹ï¼channel æ¯ç¨æ¥éä¿¡ç
å®éä¸ï¼ï¼æ°æ®æ·è´äºä¸ä»½ï¼å¹¶éè¿ channel ä¼ éï¼æ¬è´¨å°±æ¯ä¸ªéåï¼
channel åºè¯¥ç¨å¨ä»ä¹å°æ¹
æ ¸å¿ï¼éè¦éä¿¡çå°æ¹
ä¾å¦ä»¥ä¸åºæ¯ï¼
- éç¥å¹¿æ
- 交æ¢æ°æ®
- æ¾å¼åæ¥
- 并åæ§å¶
- ...
è®°ä½ï¼channel ä¸æ¯ç¨æ¥å®ç°éæºå¶çï¼è½ç¶æäºå°æ¹å¯ä»¥ç¨å®æ¥å®ç°ç±»ä¼¼è¯»åéï¼ä¿æ¤ä¸´çåºçåè½ï¼ä½ä¸è¦è¿ä¹ç¨ï¼
channel ç¨ä¾å®ç°
è¶æ¶æ§å¶
// å©ç¨ time.After å®ç° func main() { done := do() select { case <-done: // logic case <-time.After(3 * time.Second): // timeout } } func do() <-chan struct{} { done := make(chan struct{}) go func() { // do something // ... done <- struct{}{} }() return done }
åæå¿«çç»æ
æ¯è¾å¸¸è§çä¸ä¸ªåºæ¯æ¯éè¯ï¼ç¬¬ä¸ä¸ªè¯·æ±å¨æå®è¶æ¶æ¶é´å没æè¿åç»æï¼è¿æ¶éè¯ç¬¬äºæ¬¡ï¼å两次ä¸æå¿«è¿åçç»æ使ç¨ã
è¶æ¶æ§å¶å¨ä¸é¢æï¼ä¸é¢ä»£ç é¨åå°±ç®åå®ç°è°ç¨å¤æ¬¡äºã
func main() { ret := make(chan string, 3) for i := 0; i < cap(ret); i++ { go call(ret) } fmt.Println(<-ret) } func call(ret chan<- string) { // do something // ... ret <- "result" }
éå¶æ大并åæ°
// æ大并åæ°ä¸º 2 limits := make(chan struct{}, 2) for i := 0; i < 10; i++ { go func() { // ç¼å²åºæ»¡äºå°±ä¼é»å¡å¨è¿ limits <- struct{}{} do() <-limits }() }
for...range ä¼å
for ... range c { do } è¿ç§åæ³ç¸å½äº if _, ok := <-c; ok { do }
func main() { c := make(chan int, 20) go func() { for i := 0; i < 10; i++ { c <- i } close(c) }() // å½ c 被å³éåï¼åå®éé¢çåç´ å°±ä¼è·³åºå¾ªç¯ for x := range c { fmt.Println(x) } }
å¤ä¸ª goroutine åæ¥ååº
å©ç¨ close 广æ
func main() { c := make(chan struct{}) for i := 0; i < 5; i++ { go do(c) } close(c) } func do(c <-chan struct{}) { // ä¼é»å¡ç´å°æ¶å° close <-c fmt.Println("hello") }
éé»å¡ç select
select æ¬èº«æ¯é»å¡çï¼å½ææåæ¯é½ä¸æ»¡è¶³å°±ä¼ä¸ç´é»å¡ï¼å¦ææ³ä¸é»å¡ï¼é£ä¹ä¸ä¸ªä»ä¹é½ä¸å¹²ç default åæ¯æ¯æ好çéæ©
select { case <-done: return default: }
for{select{}} ç»æ¢
å°½éä¸è¦ç¨ break label å½¢å¼ï¼èæ¯æç»æ¢å¾ªç¯çæ¡ä»¶æ¾å° for æ¡ä»¶éæ¥å®ç°
for ok { select { case ch <- 0: case <-done: ok = false } }
channel ç¹æ§
åºç¡ç¹æ§
æä½ | å¼ä¸º nil ç channel | 被å³éç channel | æ£å¸¸ç channel |
---|---|---|---|
close | panic | panic | æåå³é |
c<- | æ°¸è¿é»å¡ | panic | é»å¡ææååé |
<-c | æ°¸è¿é»å¡ | æ°¸è¿ä¸é»å¡ | é»å¡ææåæ¥æ¶ |
happens-before ç¹æ§
- æ ç¼å²æ¶ï¼æ¥æ¶ happens-before åé
- ä»»ä½æåµä¸ï¼åé happens-before æ¥æ¶
- close happens-before æ¥æ¶
åè
https://go101.org/article/channel.html
https://golang.org/doc/effective_go.html#channels
以ä¸å°±æ¯æ¬æçå¨é¨å容ï¼å¸æ对大家çå¦ä¹ ææ帮å©ï¼ä¹å¸æ大家å¤å¤æ¯æèæ¬ä¹å®¶ã