注意事项:
1、channel智能存放指定的数据类型
2、channel的数据放满后不能再存放了
3、如果从channel取出数据后可以继续存放
4、在没有使用协程的情况下,channel数据取完了再去,报deadlock
可以声明管道只读和只写: int <- inChan; intChan <- int
使用select可以解决从管道取数据的阻塞问题(不知道什么时候退出管道时使用)
select语句包含的候选分支中的case表达式都会在该语句执行开始时先被求值,并且求值的顺序是依从代码编写的顺序从上到下的。结合上一条规则,在select语句开始执行时,排在最上边的候选分支中最左边的表达式会最先被求值,然后是它右边的表达式。仅当最上边的候选分支中的所有表达式都被求值完毕后,从上边数第二个候选分支中的表达式才会被求值,顺序同样是从左到右,然后是第三个候选分支、第四个候选分支,以此类推。
仅当select语句中的所有case表达式都被求值完毕后,它才会开始选择候选分支。这时候,它只会挑选满足选择条件的候选分支执行。如果所有的候选分支都不满足选择条件,那么默认分支就会被执行。如果这时没有默认分支,那么select语句就会立即进入阻塞状态,直到至少有一个候选分支满足选择条件为止。一旦有一个候选分支满足选择条件,select语句(或者说它所在的 goroutine)就会被唤醒,这个候选分支就会被执行。
对于每一个case表达式,如果其中的发送表达式或者接收表达式在被求值时,相应的操作正处于阻塞状态,那么对该case表达式的求值就是不成功的。在这种情况下,我们可以说,这个case表达式所在的候选分支是不满足选择条件的。
仅当select语句中的所有case表达式都被求值完毕后,它才会开始选择候选分支。这时候,它只会挑选满足选择条件的候选分支执行。如果所有的候选分支都不满足选择条件,那么默认分支就会被执行。如果这时没有默认分支,那么select语句就会立即进入阻塞状态,直到至少有一个候选分支满足选择条件为止。一旦有一个候选分支满足选择条件,select语句(或者说它所在的 goroutine)就会被唤醒,这个候选分支就会被执行。
如果select语句发现同时有多个候选分支满足选择条件,那么它就会用一种伪随机的算法在这些分支中选择一个并执行。注意,即使select语句是在被唤醒时发现的这种情况,也会这样做。
一条select语句中只能够有一个默认分支。并且,默认分支只在无候选分支可选时才会被执行,这与它的编写位置无关。
单向通道:
单向通道最主要的用途就是约束其他代码的行为
func SendInt(ch chan<- int) { ch <- rand.Intn(1000) } type Notifier interface { SendInt(ch chan<- int) } intChan1 := make(chan int, 3) SendInt(intChan1)
这种约束一般会出现在接口类型声明中的某个方法定义上,尤其是在我们编写模板代码或者可扩展的程序库的时候。只需要把一个元素类型匹配的双向通道传给它就行了,没必要用发送通道,因为 Go 语言在这种情况下会自动地把双向通道转换为函数所需的单向通道
func getIntChan() <-chan int { num := 5 ch := make(chan int, num) for i := 0; i < num; i++ { ch <- i } close(ch) return ch }
在另一个方面,我们还可以在函数声明的结果列表中使用单向通道
声明写入读取
var intChan chan int intChan = make(chan int, 5) intChan <- 5 intChan <- 6 intChan <- 7 f1 := <- intChan f2 := <- intChan f3 := <- intChan fmt.Println(f1, f2, f3) fmt.Println(intChan, &intChan)
//存放map
var mapChan chan map[string]string
mapChan = make(chan map[string]string, 5)
map1 := make(map[string]string, 2)
map1["name"] = "caoxt"
map1["age"] = "26"
map2 := make(map[string]string, 2)
map2["name"] = "caoxt2"
map2["age"] = "27"
mapChan <- map1
mapChan <- map2
f1 := <- mapChan
f2 := <- mapChan
f3 := <- mapChan
fmt.Println(f1["name"], f2["age"])
//存放结构体
var perChan chan Person
perChan = make(chan Person, 5)
p1 := Person{"caoxt", 21}
p2 := Person{"caoxt2", 22}
p3 := Person{"caoxt3", 23}
perChan <- p1
perChan <- p2
perChan <- p3
f1 := <- perChan
f2 := <- perChan
f3 := <- perChan
fmt.Println(f1.name, f2.age, f3.name)
//存放指针类型
var perChan chan *Person
perChan = make(chan *Person, 5)
p1 := Person{"caoxt", 31}
p2 := Person{"caoxt2", 32}
p3 := Person{"caoxt3", 33}
perChan <- &p1
perChan <- &p2
perChan <- &p3
f1 := <- perChan
f2 := <- perChan
f3 := <- perChan
fmt.Println(f1.name, f2.age, f3.name)