这是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 |
package main import ( "fmt" "time" "strconv" ) func makeCakeAndSend(cs chan string, count int) { for i := 1; i <= count; i++ { cakeName := "Strawberry Cake " + strconv.Itoa(i) cs <- cakeName //send a strawberry cake } } func receiveCakeAndPack(cs chan string) { for s := range cs { 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) } |
1 2 3 4 5 |
Packing received cake: Strawberry Cake 1 Packing received cake: Strawberry Cake 2 Packing received cake: Strawberry Cake 3 Packing received cake: Strawberry Cake 4 Packing received cake: Strawberry Cake 5 |
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 |
package main import ( "fmt" "time" "strconv" ) func makeCakeAndSend(cs chan string, flavor string, count int) { for i := 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 { case cakeName, 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) } case cakeName, 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) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Waiting for a new cake ... Received from Strawberry channel. Now packing Strawberry Cake 1 Waiting for a new cake ... Received from Chocolate channel. Now packing Chocolate Cake 1 Waiting for a new cake ... Received from Chocolate channel. Now packing Chocolate Cake 2 Waiting for a new cake ... Received from Strawberry channel. Now packing Strawberry Cake 2 Waiting for a new cake ... Received from Strawberry channel. Now packing Strawberry Cake 3 Waiting for a new cake ... Received from Chocolate channel. Now packing Chocolate Cake 3 Waiting for a new cake ... ... Strawberry channel closed! Waiting for a new cake ... ... Chocolate channel closed! |
select 会一直等待等到某个 case 语句完成, 也就是等到成功从 ch1 或者 ch2 中读到数据。 则 select 语句结束
有疑问加站长微信联系(非本文作者)