这是Channels in go的第二篇,这篇主要讲range and select ,第一篇可以打开这个链接 https://xiequan.info/channels-in-go/ 。
接收Channle的数据的时候我们会遇到,什么时候需要停止等待数据。有更多数据,还是已经全部完成?我们是继续等待还是继续?一种方法就是不断的轮询和检查通道是否已经关闭,但是这种方法并不是特别有效。
Go提供了range关键词,当它与Channel 一起使用的时候他会等待channel的关闭。
package main import ( "fmt" "time" "strconv" ) funcmakeCakeAndSend(cschanstring, countint) { for i := 1; i <= count; i++ { cakeName := "Strawberry Cake " + strconv.Itoa(i) cs <- cakeName //send a strawberry cake } } funcreceiveCakeAndPack(cschanstring) { for s := range cs { fmt.Println("Packing received cake: ", s) } } funcmain() { cs := make(chanstring) gomakeCakeAndSend(cs, 5) goreceiveCakeAndPack(cs) //sleep for a while so that the program doesn’t exit immediately time.Sleep(3 * 1e9) }
Packingreceivedcake: StrawberryCake 1 Packingreceivedcake: StrawberryCake 2 Packingreceivedcake: StrawberryCake 3 Packingreceivedcake: StrawberryCake 4 Packingreceivedcake: StrawberryCake 5
golang 的 select 的功能和 select, poll, epoll
相似, 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。注意到 select 的代码形式和 switch 非常相似, 不过 select 的 case 里的操作语句只能是 IO 操作
package main import ( "fmt" "time" "strconv" ) funcmakeCakeAndSend(cschanstring, flavorstring, countint) { for i := 1; i <= count; i++ { cakeName := flavor + " Cake " + strconv.Itoa(i) cs <- cakeName //send a strawberry cake } close(cs) } funcreceiveCakeAndPack(strbry_cschanstring, choco_cschanstring) { 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) } } } } funcmain() { strbry_cs := make(chanstring) choco_cs := make(chanstring) //two cake makers gomakeCakeAndSend(choco_cs, "Chocolate", 3) //make 3 chocolate cakes and send gomakeCakeAndSend(strbry_cs, "Strawberry", 3) //make 3 strawberry cakes and send //one cake receiver and packer goreceiveCakeAndPack(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) }
Waitingfor a new cake ... ReceivedfromStrawberrychannel. NowpackingStrawberryCake 1 Waitingfor a new cake ... ReceivedfromChocolatechannel. NowpackingChocolateCake 1 Waitingfor a new cake ... ReceivedfromChocolatechannel. NowpackingChocolateCake 2 Waitingfor a new cake ... ReceivedfromStrawberrychannel. NowpackingStrawberryCake 2 Waitingfor a new cake ... ReceivedfromStrawberrychannel. NowpackingStrawberryCake 3 Waitingfor a new cake ... ReceivedfromChocolatechannel. NowpackingChocolateCake 3 Waitingfor a new cake ... ... Strawberrychannelclosed! Waitingfor a new cake ... ... Chocolatechannelclosed!
select 会一直等待等到某个 case 语句完成, 也就是等到成功从 ch1 或者 ch2 中读到数据。 则 select 语句结束
Channels in Go range and select