浅谈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
以ä¸å°±æ¯æ¬æçå¨é¨å容ï¼å¸æå¯¹å¤§å®¶çå¦ä¹ ææå¸®å©ï¼ä¹å¸æå¤§å®¶å¤å¤æ¯æèæ¬ä¹å®¶ã