这是Channels in go的第二篇,这篇主要讲range and select ,第一篇可以打开这个链接https://xiequan.info/channels-in-go/。
接收Channle的数据的时候我们会遇到,什么时候需要停止等待数据。有更多数据,还是已经全部完成?我们是继续等待还是继续?一种方法就是不断的轮询和检查通道是否已经关闭,但是这种方法并不是特别有效。
Channels and range
Go提供了range关键词,当它与Channel 一起使用的时候他会等待channel的关闭。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
packagemain
import(
"fmt"
"time"
"strconv"
)
func makeCakeAndSend(cs chan string,count int){
fori:=1;i<=count;i++{
cakeName:="Strawberry Cake "+strconv.Itoa(i)
cs<-cakeName//send a strawberry cake
}
}
func receiveCakeAndPack(cs chan string){
fors:=rangecs{
fmt.Println("Packing received cake: ",s)
}
}
func main(){
cs:=make(chan string)
go makeCakeAndSend(cs,5)
go receiveCakeAndPack(cs)
//sleep for a while so that the program doesn’t exit immediately
time.Sleep(3*1e9)
}
Packing received cake:Strawberry Cake1
Packing received cake:Strawberry Cake2
Packing received cake:Strawberry Cake3
Packing received cake:Strawberry Cake4
Packing received cake:Strawberry Cake5
Channels and select
golang 的 select 的功能和 select, poll, epoll 相似, 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。注意到 select 的代码形式和 switch 非常相似, 不过 select 的 case 里的操作语句只能是 IO 操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
packagemain
import(
"fmt"
"time"
"strconv"
)
func makeCakeAndSend(cs chan string,flavor string,count int){
fori:=1;i<=count;i++{
cakeName:=flavor+" Cake "+strconv.Itoa(i)
cs<-cakeName//send a strawberry cake
}
close(cs)
}
func receiveCakeAndPack(strbry_cs chan string,choco_cs chan string){
strbry_closed,choco_closed:=false,false
for{
//if both channels are closed then we can stop
if(strbry_closed&&choco_closed){return}
fmt.Println("Waiting for a new cake ...")
select{
casecakeName,strbry_ok:=<-strbry_cs:
if(!strbry_ok){
strbry_closed=true
fmt.Println(" ... Strawberry channel closed!")
}else{
fmt.Println("Received from Strawberry channel. Now packing",cakeName)
}
casecakeName,choco_ok:=<-choco_cs:
if(!choco_ok){
choco_closed=true
fmt.Println(" ... Chocolate channel closed!")
}else{
fmt.Println("Received from Chocolate channel. Now packing",cakeName)
}
}
}
}
func main(){
strbry_cs:=make(chan string)
choco_cs:=make(chan string)
//two cake makers
go makeCakeAndSend(choco_cs,"Chocolate",3)//make 3 chocolate cakes and send
go makeCakeAndSend(strbry_cs,"Strawberry",3)//make 3 strawberry cakes and send
//one cake receiver and packer
go receiveCakeAndPack(strbry_cs,choco_cs)//pack all cakes received on these cake channels
//sleep for a while so that the program doesn’t exit immediately
time.Sleep(2*1e9)
}
Waiting foranewcake...
Received from Strawberry channel.Now packing Strawberry Cake1
Waiting foranewcake...
Received from Chocolate channel.Now packing Chocolate Cake1
Waiting foranewcake...
Received from Chocolate channel.Now packing Chocolate Cake2
Waiting foranewcake...
Received from Strawberry channel.Now packing Strawberry Cake2
Waiting foranewcake...
Received from Strawberry channel.Now packing Strawberry Cake3
Waiting foranewcake...
Received from Chocolate channel.Now packing Chocolate Cake3
Waiting foranewcake...
...Strawberry channel closed!
Waiting foranewcake...
...Chocolate channel closed!
select 会一直等待等到某个 case 语句完成, 也就是等到成功从 ch1 或者 ch2 中读到数据。 则 select 语句结束
Channels in Go range and select