28.并发的简单使用
import (
"fmt"
"time"
)
func say(str string){
for i:=0;i<5;i++{
time.Sleep(1000*time.Millisecond)
fmt.Println(str)
}
}
func main() {
go say("f1")
say("f2")
}
29.不带缓冲的通道
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum
}
func main() {
s := []int{1, 2, 3, 4, 5}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c
fmt.Println(x, y)
}
分析:不带缓冲的通道就是默认的,在通道收到数据时,必须要有一个接收端去取数据,在该实例中,sum变量被放进通道之前,主函数就运行到<-c了,就有接收端不断想从通道取值,只是通道中还没有数据罢了,于是就形成阻塞,主函数无法接着往下运行,只有当成功取得数据后,阻塞解除,才能接着运行
30.带缓冲的通道
func main() {
ch:=make(chan int,2)
ch<-1
ch<-2
fmt.Println(<-ch)
fmt.Println(<-ch)
}
分析:带缓冲的通道不需要一定要有一个接收端去取数据,不过由于缓冲区的大小是有限的,所以还是必须有接收端来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了
31.select的使用(一)
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(3 * time.Second)
ch1 <- 3
}()
go func() {
time.Sleep(3 * time.Second)
ch2 <- 5
}()
select {
case <-ch1:
fmt.Println("ch1")
case <-ch2:
fmt.Println("ch2")
default:
fmt.Println("default")
}
}
分析:当程序运行到select时,发现case<-ch1是无法取数据的,case<-ch2也是无法取数据的,因为小于3s,所以这两个case形成阻塞,无法执行,当没有case可执行时,就会去执行default的语句
// default:
// fmt.Println("default")
分析:把default注释掉,程序只能等待哪个case能先打破阻塞,就先执行哪个case,若有好几个case都可以执行,那就会随机公平地选一个来执行
32.select的使用(二)
var ch1, ch2 chan int
var ch = []chan int{ch1, ch2}
var number = []int{0, 1, 2, 3, 4, 5}
func main() {
select {
case getChan(0) <- getNumber(2):
fmt.Println("case1")
case getChan(1) <- getNumber(3):
fmt.Println("case2")
default:
fmt.Println("default")
}
}
func getNumber(i int) int {
fmt.Println("number", i)
return number[i]
}
func getChan(i int) chan int {
fmt.Println("chan", i)
return ch[i]
}
分析:所有case的channel表达式都会被求值,从左到右,从上到下,它是先把所有表达式都走一遍,才会随机公平选case来执行,或者发现无case满足,选default来执行,在该实例中,无法向chan写入数据,因为没有接收端去取数据,所以走了default