目录
select
package main import "sync" func main() { var wg sync.WaitGroup foo := make(chan int) bar := make(chan int) wg.Add(1) go func() { defer wg.Done() select { case foo <- <-bar: default: println("default") } }() wg.Wait() }
go func select default
原因文章也解释了,Go 语言规范中有这么一句:
For all the cases in the statement, the channel operands of receive operations and the channel and right-hand-side expressions of send statements are evaluated exactly once, in source order, upon entering the “select” statement. The result is a set of channels to receive from or send to, and the corresponding values to send. Any side effects in that evaluation will occur irrespective of which (if any) communication operation is selected to proceed. Expressions on the left-hand side of a RecvStmt with a short variable declaration or assignment are not yet evaluated.
不知道大家看懂没有?于是,最后来了一个例子验证你是否理解了:为什么每次都是输出一半数据,然后死锁?(同样,这里可以运行查看结果:https://play.studygolang.com/p/zoJtTzI7K5T)
package main import ( "fmt" "time" ) func talk(msg string, sleep int) <-chan string { ch := make(chan string) go func() { for i := 0; i <5; i++ { ch <- fmt.Sprintf("%s %d", msg, i) time.Sleep(time.Duration(sleep) * time.Millisecond) } }() return ch } func fanIn(input1, input2 <-chan string) <-chan string { ch := make(chan string) go func() { for { select { case ch <- <-input1: case ch <- <-input2: } } }() return ch } func main() { ch := fanIn(talk("A", 10), talk("B", 1000)) for i := 0; i <10; i++ { fmt.Printf("%q\n", <-ch) } }
有没有这种感觉:
这是 StackOverflow 上的一个问题:https://stackoverflow.com/questions/51167940/chained-channel-operations-in-a-single-select-case。
select case channel fanIn
select { case ch <- <-input1: case ch <- <-input2: }
如果改为这样就一切正常:
select { case t := <-input1: ch <- t case t := <-input2: ch <- t }
结合这个更复杂的例子分析 Go 语言规范中的那句话。
select
比如:
// ch 是一个 chan int; // getVal() 返回 int // input 是 chan int // getch() 返回 chan int select { case ch <- getVal(): case ch <- <-input: case getch() <- 1: case <- getch(): }
case getVal() <-input getch()
package main import ( "fmt" ) func main() { ch := make(chan int) go func() { select { case ch <- getVal(1): fmt.Println("in first case") case ch <- getVal(2): fmt.Println("in second case") default: fmt.Println("default") } }() fmt.Println("The val:", <-ch) } func getVal(i int) int { fmt.Println("getVal, i=", i) return i }
select casegetVal() getVal(1) getVal(2)
getVal, i= 1 getVal, i= 2
你可以仔细琢磨一下。
StackOverflow
每次进入以下 select 语句时:
select { case ch <- <-input1: case ch <- <-input2: }
<-input1 和 <-input2 <-input1 和 <-input2
main
虽然这是一个小细节,但实际开发中还是有可能出现的。比如文章提到的例子写法:
// ch 是一个 chan int; // getVal() 返回 int // input 是 chan int // getch() 返回 chan int select { case ch <- getVal(): case ch <- <-input: case getch() <- 1: case <- getch(): }
select
time.After select
time.After
package main import ( "time" ) func main() { ch := make(chan int, 10) go func() { var i = 1 for { i++ ch <- i } }() for { select { case x := <- ch: println(x) case <- time.After(30 * time.Second): println(time.Now().Unix()) } } }