go中的關鍵字-select

1. select的使用

  定義:在golang裡頭select的功能與epoll(nginx)/poll/select的功能類似,都是堅挺IO操作,當IO操作發生的時候,觸發相應的動作。

1.1 一些使用規範

  在Go的語言規範中,select中的case的執行順序是隨機的,當有多個case都可以運行,select會隨機公平地選出一個執行,其他的便不會執行:

 1 package main
 2 
 3 import "fmt"
 4 
 5 func main() {
 6     ch := make (chan int, 1)
 7 
 8     ch<-1
 9     select {
10     case <-ch:
11         fmt.Println("隨機一")
12     case <-ch:
13         fmt.Println("隨機二n")
14     }
15 }

  輸出內容為隨機一二里面的任意一個。

  case後面必須是channel操作,否則報錯;default子句總是可運行的,所以沒有default的select才會阻塞等待事件 ;沒有運行的case,那麼將會阻塞事件發生報錯(死鎖)。

1.2 select的應用場景

timeout 機制(超時判斷)
 1 package main
 2 
 3 import (
 4     "fmt"
 5     "time"
 6 )
 7 
 8 func main() {
 9     timeout := make (chan bool, 1)
10     go func() {
11         time.Sleep(1*time.Second) // 休眠1s,如果超過1s還沒I操作則認為超時,通知select已經超時啦~
12         timeout <- true
13     }()
14     ch := make (chan int)
15     select {
16     case <- ch:
17     case <- timeout:
18         fmt.Println("超時啦!")
19     }
20 }

  也可以這麼寫:

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "time"
 6 )
 7 
 8 func main() {
 9     ch := make (chan int)
10     select {
11     case <-ch:
12     case <-time.After(time.Second * 1): // 利用time來實現,After代表多少時間后執行輸出東西
13         fmt.Println("超時啦!")
14     }
15 }

  判斷channel是否阻塞(或者說channel是否已經滿了)

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func main() {
 8     ch := make (chan int, 1)  // 注意這裏給的容量是1
 9     ch <- 1
10     select {
11     case ch <- 2:
12     default:
13         fmt.Println("通道channel已經滿啦,塞不下東西了!")
14     }
15 }

  退出機制

 1 package main
 2 
 3 import (
 4     "fmt"
 5     "time"
 6 )
 7 
 8 func main() {
 9     i := 0
10     ch := make(chan string, 0)
11     defer func() {
12         close(ch)
13     }()
14 
15     go func() {
16         DONE: 
17         for {
18             time.Sleep(1*time.Second)
19             fmt.Println(time.Now().Unix())
20             i++
21 
22             select {
23             case m := <-ch:
24                 println(m)
25                 break DONE // 跳出 select 和 for 循環
26             default:
27             }
28         }
29     }()
30 
31     time.Sleep(time.Second * 4)
32     ch<-"stop"
33 }

2. select的實現

  select-case中的chan操作編譯成了if-else。如:

1  select {
2  case v = <-c:
3          ...foo
4  default:
5          ...bar
6  }

  會被編譯為:

1  if selectnbrecv(&v, c) {
2          ...foo
3  } else {
4          ...bar
5  }

  類似地

1  select {
2  case v, ok = <-c:
3      ... foo
4  default:
5      ... bar
6  }

  會被編譯為:

1  if c != nil && selectnbrecv2(&v, &ok, c) {
2      ... foo
3  } else {
4      ... bar
5  }

  selectnbrecv函數只是簡單地調用runtime.chanrecv函數,不過是設置了一個參數,告訴當runtime.chanrecv函數,當不能完成操作時不要阻塞,而是返回失敗。也就是說,所有的select操作其實都僅僅是被換成了if-else判斷,底層調用的不阻塞的通道操作函數。

  在Go的語言規範中,select中的case的執行順序是隨機的,那麼,如何實現隨機呢?

  select和case關鍵字使用了下面的結構體:

1 struct    Scase
2   {
3       SudoG    sg;            // must be first member (cast to Scase)
4       Hchan*    chan;        // chan
5       byte*    pc;            // return pc
6       uint16    kind;
7       uint16    so;            // vararg of selected bool
8       bool*    receivedp;    // pointer to received bool (recv2)
9   };
1  struct    Select
2      {
3      uint16    tcase;            // 總的scase[]數量
4      uint16    ncase;            // 當前填充了的scase[]數量
5      uint16*    pollorder;        // case的poll次序
6      Hchan**    lockorder;        // channel的鎖住的次序
7      Scase    scase[1];        // 每個case會在結構體里有一個Scase,順序是按出現的次序
8  };

  每個select都對應一個Select結構體。在Select數據結構中有個Scase數組,記錄下了每一個case,而Scase中包含了Hchan。然後pollorder數組將元素隨機排列,這樣就可以將Scase亂序了。

 3. select死鎖

  select不注意也會發生死鎖,分兩種情況:

  如果沒有數據需要發送,select中又存在接收通道數據的語句,那麼將發送死鎖

1 package main
2 func main() {  
3     ch := make(chan string)
4     select {
5     case <-ch:
6     }
7 }

  預防的話加default。

  空select,也會引起死鎖。

1 package main
2 
3 func main() {  
4     select {}
5 }

 4. select和switch的區別

select

select只能應用於channel的操作,既可以用於channel的數據接收,也可以用於channel的數據發送。如果select的多個分支都滿足條件,則會隨機的選取其中一個滿足條件的分支, 如規範中所述:

If multiple cases can proceed, a uniform pseudo-random choice is made to decide which single communication will execute.

`case`語句的表達式可以為一個變量或者兩個變量賦值。有default語句。

31 package main                                                                                                                                              32 import "time"
33 import "fmt"                                                                                                                                              
35 func main() {                                                                                                                                             36     c1 := make(chan string)
37     c2 := make(chan string)                                                                                                                               38     go func() {
39         time.Sleep(time.Second * 1)                                                                                                                       40         c1 <- "one"
41     }()                                                                                                                                                   42     go func() {
43         time.Sleep(time.Second * 2)                                                                                                                       44         c2 <- "two"
45     }()                                                                                                                                                   46     for i := 0; i < 2; i++ {
47         select {                                                                                                                                          48             case msg1 := <-c1:
49             fmt.Println("received", msg1)          
50 case msg2 := <-c2: 51 fmt.Println("received", msg2)
52 } 53 }

switch

  switch可以為各種類型進行分支操作, 設置可以為接口類型進行分支判斷(通過i.(type))。switch 分支是順序執行的,這和select不同。

 1 package main                  
 2 import "fmt"
 3 import "time"  
 4 
 5 func main() {                                                                                                                             
 6      i := 2
 7      fmt.Print("Write ", i, " as ")  
 8      switch i {
 9          case 1:
10          fmt.Println("one")
11          case 2:                                                                                                                                  
12          fmt.Println("two")
13          case 3:                                                                                                                      
14          fmt.Println("three")
15      }                                                                                                                                             
16      switch time.Now().Weekday() {
17          case time.Saturday, time.Sunday:
18          fmt.Println("It's the weekend")
19          default:                                                                                                                                      
20          fmt.Println("It's a weekday")
21      }                                                                                                                                                 
22      t := time.Now()
23      switch {                                                                                                                                         
24          case t.Hour() < 12:
25          fmt.Println("It's before noon")                                                                                                              
26          default:
27          fmt.Println("It's after noon")                                                                                                                  
28      }
29      whatAmI := func(i interface{}) {                                                                                                                   
30          switch t := i.(type) {
31              case bool:                                                                                                                              
32              fmt.Println("I'm a bool")
33              case int:                                                                                                                                 
34              fmt.Println("I'm an int")
35              default:                                                                                                                                 
36              fmt.Printf("Don't know type %T\n", t)
37          }
38      }
39      whatAmI(true)                                                                                                                                     
40      whatAmI(1)
41      whatAmI("hey")                                                                                                                                 
42  }

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

小三通物流營運型態?

※快速運回,大陸空運推薦?

特斯拉 Model 3 大賣,電動車朝向榮景仍逢瓶頸?

電動車大廠特斯拉(Tesla)新款房車 Model 3 的預購量超出預期,市場上開始有許多分析師發言,有的說電動車即將取代傳統的汽車;有人甚至認為應該忘掉正面臨創新瓶頸的 Apple 執行長 Tim Cook,將目光移向 Tesla 創辦人 Elon Musk,稱他是偉大夢想及實踐家,其能力傲視全球的企業家,然而事實真是如此嗎?   電動車大廠特斯拉(Tesla)新款房車 Model 3 於 2016 年 3 月展開全球預售,售價 3.5 萬美元(約新台幣 110 萬元),買主只需要預付 1,000 美元(約新台幣 3 萬元)就可以訂車,此舉立刻引起市場震撼,吸引大批車迷排隊預購,光是在一天內便湧入 11 萬筆訂單,首周預購就超過 32 萬筆。  
暗藏玄機的預購書   仔細看看 Tesla 的預購合約書(其實這算不上合約書只是預購同意書而已),就可以看出到底為什麼大家會一窩蜂的搶訂。Tesla 的預購條件很簡單,任何人想要訂購 Model 3,只需要支付 1,000 美元的訂金,而且任何時間如果後悔都可以全部退還,換句話說,對消費者而言沒有任何風險;同樣的,Tesla 在文件裡也沒有寫明交車時間,檯面上說 2017 年底是「預定」交車時間,但如果交不出來或延後到 2018 甚至 2020 年,也沒有任何罰則。   放眼望去,哪家車廠會訂出這種購車合約?這樣的操作 Tesla 的目的為何?   Tesla 成立於 2003 年,到現在已經超過 12 年了,它是第一家把電動車成功推到全球市場的公司,讓電動車與高級車畫上等號,吸引到高收入客戶。Tesla 帶給人們對於未來汽車的夢想,進而推升了它的高股價,甚至比大部分賺錢的公司還要高出十幾、二十倍。美國汽車在 2015 年銷售創下歷來最佳紀錄,但福特(Ford)和通用(GM)等汽車業者股票卻大跌,股價本益比僅 5~7 倍,而 Tesla 卻能在持續虧損下,過去 3 年漲了將近 400%,比標普 500 指數與其他傳統車商要好得多。   2013 年 Tesla 進軍中國,希望拿下繼美國之後第二個龐大的電動車市場,甚至 Musk 曾揚言「中國市場很快就超越美國成為 Tesla 電動車的第一大市場」。但是 Tesla 一直無法突破瓶頸,2015 第三季結束的交車總量只有 3,025 輛,不到全球交付量 50,580 輛的十分之一。目前看起來 Tesla 要搶下中國市場,還有一段很漫長的路要走,除了中國政策的問題,無補貼、高關稅、被排除在國家標準之外,各國車廠也紛紛摩拳擦掌,準備搶食中國電動車的市場大餅。   長期的虧損也讓華爾街的分析師對 Musk 的耐心慢慢消磨殆盡,除了進軍中國沒有交出漂亮的成績單,Tesla 還是延遲交貨的慣犯,從首款電動車 Roadster、次代 Model S 到電動休旅車 Model X,從未準時交貨,Model X 甚至還延遲超過一年半。  
先求資金到位以利發展   雖然 Model 3 被定位成平價車款,它的設計沒有其他現有車款 Model S 與 Model X 複雜,但是能不能準時交貨並不是 Tesla 說了算,還是得仰賴後端生產零件的供應商是否如期交貨。Tesla 也預見可能發生的狀況,已先幫自己找替代方案,在加州費利蒙〈Fremont〉的生產工廠自行製造所需零件。   另外電池材料來源與價格,也是必須考量的因素。電動車使用鋰電池做為動力來源,除了電池本身必須非常嚴謹安全,當需求量大增時也會推升鋰材料的價格,因此未必能夠因為數量大幅成長而使價格大幅下降。2015 年第四季開始,就發生鋰電池正極材料所需的碳酸鋰缺貨,導致鋰電池廠商無法擴產,碳酸鋰每噸的市場價格也從 2013 年 9 月的 5 萬人民幣上漲到 12 萬人民幣。Model 3 都還沒做出來碳酸鋰價格就開始上漲了!   大量的電動車充電需求也代表電力基礎建設必須更新,這也不是短時間內可以做到的事,而 Tesla 垂涎欲滴的中國市場,雖然計劃擴建充電站,卻只支援中國國內的電動車品牌。超級充電站不相容、充電難的問題將進一步加劇 Tesla 的困境。   Tesla 可以在一周內拿到超過 30 萬的消費者預購同意書,並不代表真的能做到這麼多生意,連 Musk 都對 2017 年是否能順利上市不太有信心,他在發表會上說「Model 3 不太可能如期交車」。而當 2017 年時間一到,如果交不出令人滿意的 Model 3,或是首購的客戶有了不好的評價,到時候退訂的浪潮也會很兇猛的。   因此 Tesla「不訂出逾期的賠償條款」,對消費者和他們而言可謂雙贏策略。對消費者來說沒有任何風險,還可以過過 Tesla 車主的癮,於是消費者瘋狂訂購;對 Tesla 來說,可以向華爾街的分析師與市場上的投資人證明 Tesla 的潛在客戶非常龐大,有利於向資本市場募資吸金,等於是先拿到了訂單,再回頭過來向市場募資,一箭雙鵰。  
交車不順恐不利後續發展   而 2017 年是否真的能交車呢?是否真的能賣到 3.5 萬美元這麼低的價格?那是以後的事了,只要資金到位,未來要怎麼做都好說;缺少了資金和市場信心,別談以後了,Tesla 可能就要面臨後勢不振的壓力了。   Musk 在資本市場上為投資人,也為新創公司建立一個遠大的夢想並沒有什麼不對,而且手法高明了許多,但 Musk 真的能把 Cook 比下嗎?蘋果一直以來都是腳踏實地在創新,東西真的做得好賣得好,而賺大錢富可敵國才讓股票大漲的,當然做得再好的產品也會遭遇瓶頸,但是這畢竟靠的是腳踏實地的「本益比」,而不是虛幻不實的「本夢比」。   在商場上投機的確是會成功的,有時候成功的機率還不低,但是如果我們過度推崇投機,把投機說成是偉大夢想及實踐能力傲視全球,那對腳踏實地在創新的 Steven Jobs 和 Cook 也太不公平了!   (首圖來源: CC BY 2.0)   (本文授權轉載自《》─〈〉)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

Tesla年產50萬電動車牛皮吹太大,供應商坦承沒把握

特斯拉(Tesla)計畫在2018年大規模量產平價電動車Model 3,時程較原先計畫提早兩年,雖然展現特斯拉執行長穆斯克(Elon Musk)強大企圖心,但也飽受專家質疑,甚至特斯拉旗下供應商對於是否能達成目標也沒把握。   Model 3已開放預定,特斯拉目前累計收到37.3萬輛的訂單、預計2017年底開始交車。但外界所不知道的是,供應商是在三個月之前才被告知增產計畫提前,相關準備作業是否先完成令人質疑。據路透社引述知情人事消息報導指出,特斯拉最新計畫把2017年Model 3產出規模提高兩倍至10萬輛,2018年更將達成40萬輛的產出水平。   穆斯克4月28日曾在財報法說會上對分析師誇下海口,2018年整體產出規模(含Model S、Model X、Model 3)將來到50萬輛,是去年的十倍,也較預設時程快了兩年。不過Model 3設計目前還要等到6月才定案,距初次量產僅剩13個月。   電動車零組件何其多,且缺一不可,特斯拉如何在短時間內搞定供應商、備齊所有零組件,雖然並非完全不可能,但挑戰難度絕對相當高,這也考驗穆斯克的管理協調能力。值得一提的是,北美目前僅有少數汽車產線有年產50萬輛的能力,且背後都有幾十年經驗的車廠在運籌帷幄。   (本文內容由授權使用;首圖來源: CC BY 2.0)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

小三通物流營運型態?

※快速運回,大陸空運推薦?