select { case order := <-appOrders: queue <- order case order := <-inShopOrders: queue <- order }当任何一个通道接收到订单时,Partier 会将其转发到 queue 通道。
如果两个通道都有订单,其中之一将被选择。在真实的咖啡馆中,来自 inShopOrders 的订单可能会被优先处理。然而,在Go应用程序中,我们不能保证会选择哪个订单。还请注意,select 语句的每次执行只会选取一个订单,Partier 不会先选择一个订单,然后再选择另一个订单。尽管如此,在许多应用程序中,select 语句通常在 for 循环内部,使得前一次迭代中留下的订单在下一次迭代中有机会被选取。
for { select { case order := <-appOrders: queue <- order case order := <-inShopOrders: queue <- order } }但是,如果两个通道都有订单,它们将再次进行公平竞争。
for { select { case order := <-appOrders: log.Println("There is an order coming from appOrders channel") queue <- order case order := <-inShopOrders: log.Println("There is an order coming from inShopOrders channel") queue <- order default: log.Println("There is no order on both channels, I will do cleaning instead") doCleaning() } }time.After()
shouldClose := false closeHourCh := time.After(8 * time.Hour) for !shouldClose { select { case order := <-appOrders: log.Println("There is an order coming from appOrders channel") queue <- order case order := <-inShopOrders: log.Println("There is an order coming from inShopOrders channel") queue <- order case now := <-closeHourCh: log.Printf("It is %v now, the shop is closing\n", now) shouldClose = true default: log.Println("There is no order on both channels, I will go cleaning instead") doCleaning() } } log.Println("Shop is closed, I'm going home now. Bye!")在处理远程API调用时,这种技术非常常见,因为我们不能保证远程服务器何时返回或是否返回。有了 context,我们通常不需要这样做。
responseChannel := make(chan interface{}) timer := time.NewTimer(timeout) select { case resp := <-responseChannel: log.Println("Processing response") processResponse(resp) timer.Stop() case <-timer.C: log.Println("Time out, giving up") }
package main import ( "fmt" "log" "time" ) func main() { // 堆代码 duidaima.com appOrders := make(chan order, 3) inShopOrders := make(chan order, 3) queue := make(chan order, 3) go func() { for i := 0; i < 6; i++ { appOrders <- order(100 + i) time.Sleep(10 * time.Second) } close(appOrders) }() go func() { for i := 0; i < 4; i++ { inShopOrders <- order(200 + i) time.Sleep(15 * time.Second) } close(inShopOrders) }() go partier(appOrders, inShopOrders, queue) for o := range queue { log.Printf("Served %s\n", o) } log.Println("Done!") } func partier(appOrders <-chan order, inShopOrders <-chan order, queue chan<- order) { shouldClose := false closeTimeCh := time.After(1 * time.Minute) for !shouldClose { select { case ord, ok := <-appOrders: if ok { log.Printf("There is %s coming from appOrders channel\n", ord) queue <- ord } case ord, ok := <-inShopOrders: if ok { log.Printf("There is %s coming from inShopOrders channel\n", ord) queue <- ord } case now := <-closeTimeCh: log.Printf("It is %v now, the shop is closing\n", now) shouldClose = true default: log.Println("There is no order on both channels, I will go cleaning instead") doCleaning() } } close(queue) log.Println("Shop is closed, I'm going home now. Bye!") } func doCleaning() { time.Sleep(5 * time.Second) log.Println("Partier: Cleaning done") } type order int func (o order) String() string { return fmt.Sprintf("order-%02d", o) }