上周,我發布了一篇關于如何直觀解釋Golang中通道(Channel)的文章。如果你對通道仍然感到困惑,請先查看那篇文章:《Go并發可視化解釋 — Channel》。
作為一個快速復習:Partier、Candier和Stringer經營著一家咖啡店。Partier負責接受顧客的訂單,然后將這些訂單傳遞給廚房,Candier和Stringer制作咖啡。
Gophers' Cafe(Gopher咖啡館)
在本文中,我將直觀解釋select語句,這是在Go應用程序中處理并發的另一個強大工具。Gophers和他們的虛構咖啡館仍然是我的伙伴,但這次,讓我們聚焦在Partier和點單部分。
Gopher的Cafe意識到越來越多的顧客希望通過外賣應用程序在線訂購咖啡。因此,除了店內點餐外,他們還選擇了一個外賣應用程序。Partier會監視來自兩個通道的訂單,并通過另一個名為queue的通道將這些訂單轉發給Candier和Stringer。
select {case order := <-appOrders: queue <- ordercase order := <-inShopOrders: queue <- order}
當這兩個通道中的任何一個有訂單時,Partier會獲取訂單并將其轉發到queue通道。
如果這兩個通道都有訂單,將會選擇其中一個。在實際的咖啡店中,來自inShopOrders的訂單可能會被優先處理。但是,在Go應用程序中,我們無法保證哪個訂單會被選擇。還要注意,select語句的執行只會選擇一個訂單,Partier不會一次選擇兩個訂單。但是,在許多應用程序中,select語句通常嵌套在for循環中,以便在前一個迭代中剩下的訂單有機會在下一個迭代中被選擇。
select {case order := <-appOrders: queue <- ordercase order := <-inShopOrders: queue <- order}
但是,如果這兩個通道都有訂單,它們將再次進行公平競爭。
在非高峰時段,訂單不多,Partier花費大量時間在等待上。他認為,他可以通過做其他事情來更有效地利用時間,例如清理桌子。這可以通過default來實現:
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(duration)通常與select一起使用,以防止永久等待。與default不同,time.After(duration)會創建一個普通的<-chan Time,等待duration時間的流逝,然后將當前時間發送到返回的通道上。這個通道在select語句中與其他通道平等對待。正如你所看到的,select語句中的通道可以是不同類型的。
shouldClose := falsecloseHourCh := 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 := <-
本文鏈接:http://www.tebozhan.com/showinfo-26-10449-0.htmlGo并發可視化解釋 – select語句
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com