1.单向通道
单向通道常用于函数做函数的约束或接口
//只写通道
func Test1(ch chan<- int){
//在函数体中无法进行读取
ch<-1
}
//只读通道
func Test2() <-chan int {
ch :=make(chan int,3)
ch<-1
close(ch)
return ch
}
type OnlyWriteChannel interface {
WriteChannelData(ch<- int)
}
2.Select分支规则
先执行一段demo
package main
import "fmt"
var channels = [3]chan int{
nil,
make(chan int), //【1】注意这里创建了一个无缓冲通道
nil,
}
var numbers = []int{1, 2, 3}
func main() {
select {
case getChan(0) <- getNumber(0):
fmt.Println("The first candidate case is selected.")
case getChan(1) <- getNumber(1):
fmt.Println("The second candidate case is selected.")
case getChan(2) <- getNumber(2):
fmt.Println("The third candidate case is selected")
default:
fmt.Println("No candidate case is selected!")
}
}
func getNumber(i int) int {
fmt.Printf("numbers[%d]\n", i)
return numbers[i]
}
func getChan(i int) chan int {
fmt.Printf("channels[%d]\n", i)
return channels[i]
}
执行结果为选择了默认分支
channels[0]
numbers[0]
channels[1]
numbers[1]
channels[2]
numbers[2]
No candidate case is selected!
作为我这个初学者来说很好奇,select不是按理来说应该返回分支2的结果吗,怎么选择了默认分支?
这要从select选择分支的规则开始说起
首先要明白:仅当select语句中的所有case表达式都被求值完毕后,它才开始选择分支
规则:
- select语句的每一个case表达式都会至少包含一个发送或接收操作
- 分支中的case表达式都会在该语句执行开始时先被求值,并且求值顺序是从上到下,从左到右。
因此不难理解 先输出channel再输出numbers
3.对于每一个case表达式,如果在被求值时相应的操作处于阻塞状态,那么对该case表达式的求值就是不成功的,即不满足选择条件
因为demo中的channel是无缓冲的,所以分支二在求值时被阻塞
4.所有表达式求值完毕,选择分支,当有多个分支满足条件即成功,就用一种伪随机的算法选择分支执行
因此不能依赖select的case顺序 来确定业务语句的执行顺序
当没有分支时就会阻塞select直到有一个满足条件
5.只能有一个默认分支
- 每次select执行,包含的case表达式求值 和 分支选择都是独立的
如何修改?
方法1. 去掉默认分支
方法2. 使用缓冲通道
3.select与For联用如何跳出最外层循环
利用break flag机制
package main
import (
"fmt"
"time"
)
func main(){
ch :=make(chan int , 3 )
go sleep(ch)
myloop:
for {
select {
case el :=<-ch:
fmt.Printf("get data %d\n",el)
case <-time.After(time.Second) :
fmt.Println("timeout")
break myloop;
}
}
}
func sleep(ch chan int){
for {
ch<-1
time.Sleep(time.Second)
}
}
网友评论