第十章 channel select 总结
感觉channel在理解起来还有点费劲的,尤其是select的使用,既要可以读数据,又要可以写数据. 复习一下都学了哪些?然后在重点查一下select的资料 ? 一. channel的定义.?
二. select的使用一个select语句用来选择哪个case中的发送或接收操作可以被立即执行。它类似于switch语句,但是它的case涉及到channel有关的I/O操作。 select的用法与switch非常类似,由select开始一个新的选择块,每个选择条件由case语句来描述。与switch语句可以选择任何可使用相等比较的条件相比, “ select”语句的执行分几个步骤进行:
备注:RecvStmt指的就是短变量. 例如: case n := <- a1,其中的n就是短变量 示例1:select语句会一直等待,直到某个case里的IO操作可以进行) func main() { a1 := make(chan ) a2 := make(chan ) 向管道a1中放数据 go func() { time.Sleep(time.Second * ) a1 <- }() 向管道a2中放数据 ) a2 <- 使用select从管道a1,a2中读数据 select { case n := <- a1: fmt.Println(n) case n:= <- a2: fmt.Println(n) } time.Sleep(time.Second * 10) } 一直等着,知道2s后a1通道有数据执行第一个case后打印,5s后a2通道有数据,select执行第二个case取出 这个demo可以更好的说明,select一直在阻塞等待. 知道有符合条件的case执行.? for { a1: fmt.Println(n) time.Sleep(time.Second) a2: fmt.Println(n) time.Sleep(time.Second * ) default: fmt.Println(default) time.Sleep(time.Second * ) } } time.Sleep(time.Second * ) } ? 示例2:select语句的多个case同时满足条件,执行那个case是随机的同样是上面的demo,两个时间都改为2s. 发现,运行结果,有时打印的是1,有时打印的是2 func main() { a1 := make(chan go func() { time.Sleep(time.Second * 2) a1 <- go func() { time.Sleep(time.Second * 2) a2 <- ) } 示例3:所有channel表达式都会被求值、所有被发送的表达式都会被求值。求值顺序:自上而下、从左到右.package main import " var a1 = make(chan ) var a2 = make(chan ) var a = []chan {a1,a2} var num = []int {1,1)">2,1)">3,1)">4,1)">5,1)">} func main() { go func(a chan ) { fmt.Println(<- a) }(a1) i:= 1 { case getChan(i- getNumber(i,num) : fmt.Printf(把数字 %d 放在第 %d 通道里,i,i) case n := <- getChan(i-把数字从通道 %d 里取出来 %d nint) chan { fmt.Println(chanreturn a[i] } func getNumber(i int) { fmt.Println(num n[i] } 结果 ? ? ?在print之前,执行了两遍getChan,一遍getNumber 示例4 break关键字结束selectch1 := make(chan ) ch2 := make(chan ) ch1 <- ch2 <- 5 case <- ch1: fmt.Println(ch1 selected.) break fmt.Println(ch1 selected after break ch2: fmt.Println(ch2 selected.) fmt.Println(ch2 selected without break) } 很明显,ch1和ch2两个通道都可以读取到值,所以系统会随机选择一个case执行。我们发现选择执行ch1的case时,由于有break关键字只执行了一句 ch1 selected. Process finished with exit code 0 但是,当系统选择ch2的case时,打印结果为: ch2 selected. ch2 selected without Process finished with exit code 0 如此就显而易见,break关键字在select中的作用。 ? 示例5: 最后再来看一下我们的那个复杂的demomath/rand ) func generator() chan { c := make(chan ) i := 0 go func() { { time.Sleep(time.Duration(rand.Intn(1500)) * time.Millisecond) i++ c <- i } }() c } func createWorker(i { out := make(chan ) go func() { for cc := range out { time.Sleep(time.Second*) fmt.Printf(管道a%d,value:%dnreturn } func main() { var a1 = generator() var a2 = generator() c := createWorker( { a1: c <- n a2: c <-/*default: fmt.Println("default") time.Sleep(time.Second)*/ } } } 这里定义了两个生产者管道,一个消费者管道,然后同时工作 接下来想做的事是: 从生成数据的管道中取出数据,保存到消费管道中,消费数据. ) func generator(num fmt.Printf(管道编号: %d,i值:%d n取数据--管道a%d,1)">var a1 = generator(var a2 = generator() c := createWorker() n := 0 a1: a2: case c <- n: 从管道中取出的数据,放到消费者管道中 } } } 这样有一个问题,当消费数据速度慢时,会丢数据. 解决这个问题,使用一个数组来接收 var values []int var activeValue int 这里重新定义一个channel的原因是: 如果,values为空. 会将一个nil放入到c中. 然后执行values = values[1:]会报下标越界. 所以定义activeChannel. 初始值时nil. 给一个nil管道放数据, 不会执行,会一直等待 var activechannel chan if len(values) > { activeValue = values[] activechannel = c } a1: values = append(values,n) a2: values =case activechannel <- activeValue: // values = values[:] } } } 将数组中的数据取出,放入channel的时候,可以成功. 但是汇报异常. 接下来,写个定时器,让程序10秒后自动退出? 定时发送任务. 返回的是一个时间的channel ta := time.After(time.Second * 10) // values = values[:] case <- ta: //每10秒从channel中取出数据,fmt.Println("bye") return } } } 我们定义每超过800ms打印一次超时,这个和上一个定时的区别是: 他是两个case之间输出数据的时间>800. 而上一个的10秒钟是整个程序执行10秒钟 ? ) // 定时发送任务. 返回的是一个时间的channel ta := time.After(time.Second * 10) :] case <- time.After(time.Millisecond * 800): fmt.Println("timeout") } } } 最后一个,定时打印每秒钟数组中积压的数据 定时发送任务. 返回的是一个时间的channel ta := time.After(time.Second * 定时器,返回的也是一个管道. 每秒往管道中放一个数据 tick := time.Tick(time.Second) case <- ta: 每10秒从channel中取出数据, fmt.Println(byereturn case <- time.After(time.Millisecond * 800): fmt.Println(timeout) case <- tick: fmt.Println("len:",len(values)) } } } ? ? ? ? ? 参考文献: 1.?https://www.jianshu.com/p/2a1146dc42c3 2.?https://blog.csdn.net/dwjpeng2/article/details/81700147 ? (编辑:北几岛) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |