go channel的一些技巧

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

1. 一個已經被關閉的 channel 永遠都不會阻塞。當一個 channel 一旦被關閉,就不能再向這個 channel 發送資料,但仍然可以嘗試從 channel 中擷取值。

2. 已經被關閉的 channel 會即時返回。


package mainimport ("fmt""sync""time")func main() {const n = 100000finish := make(chan bool)var done sync.WaitGroupfor i := 0; i < n; i++ {done.Add(1)go func() {select {case <-time.After(1 * time.Hour):case <-finish:}done.Done()}()}t0 := time.Now()close(finish)done.Wait()fmt.Printf("waited %v for %d goroutines to stop\n", time.Since(t0), n)}


當 finish channel 被關閉後,它會立刻返回。那麼所有等待接收 time.After channel 或 finish 的 goroutine 的 select 語句就立刻完成了,並且 goroutine 在調用 done.Done() 來減少 WaitGroup 計數器後退出。這個強大的機制在無需知道未知數量的 goroutine 的任何細節而向它們發送訊號而成為可能,同時也不用擔心死結。

當 close(finish) 依賴於關閉 channel 的訊息機制,而沒有資料收發時,將 finish 定義為 type chan struct{} 表示 channel 沒有任何資料;只對其關閉的特性感興趣。即:finish := make(chan struct{}) 

3. 當 channel 的值尚未進行初始化或賦值為 nil 時,永遠都是阻塞的。

WaitMany() 中,一旦接收到一個值,就將 a 或 b 的引用設定為 nil。當 nil channel 是 select 語句的一部分時,它實際上會被忽略,因此,將 a 設定為 nil 便會將其從 select 中移除,僅僅留下 b 等待它被關閉,進而退出迴圈。

4. slice append函數的各種技巧

//添加切片a = append(a, b, c, d)//將切片b添加至切片aa=append(a, b...)//複製切片b := make([]int, len(a))copy(b, a)//刪除指定位置元素[i:j]a = append(a[:i], a[j:]...)//刪除第n個元素a = append(a[:n], a[n+1:]...)//擴充n個空元素a = append(a, make([]int, n)...)//在第i個位置插入j個空元素a = append(a[:i], append(make([]int, j), a[i:]...)...)//在第i個位置插入元素xa = append(a[:i], append([]int{x}, a[i:]...)...)//在i個位置插入切片a = append(a[:i], append([]int{x, y}, a[i:]...)...)

其中刪除操作就是覆蓋;而插入操作需要注意不能覆蓋掉插入位置及以後的元素。

5. 關於string與[]byte、[]rune相互轉換的問題:

str := "hello世界"   sli := []rune(str)   []rune 是go內建的函數,會將字串按utf8編碼轉換為{h,e,l,l,o,世,界}對應的數字{104,101,108,108,111,19990,30028}   byt := []byte(str)   []byte 是go內建函數,會將str轉換為byte切片{104,101,108,108,111,228,184,150,231,149,140}   for _,c := range str{     println(c)   }   len(str) 返回 11    len返回字串byte長度   go 中的字元可以是 ASCII/中文 ..    s := '你'   string(sli)/string(byt) 都返回 "hello世界"       string()是go內建函數 無論是[]rune或者[]byte 都能通過string()函數返回相應的字串
6. 在使用多個 goroutine 列印內容時,經常因為使用 chan 不恰當而 導致主線程未等待其它 goroutine 全部執行完畢而匆匆推出,造成列印內容不全的問題,這裡對其中一種情況進行講解。

package main import (         "fmt"        "runtime") // 從 1 至 1 億迴圈疊加,並列印結果。 func print(c chan bool, n int) {         x := 0         for i := 1; i <= 100000000; i++ {                 x += i         }         fmt.Println(n, x)         if n == 9 {                 c <- true        } }   func main() {         // 使用多核運行程式         runtime.GOMAXPROCS(runtime.NumCPU())         c := make(chan bool)         for i := 0; i < 10; i++ {                 go print(c, i)         }         <-c         fmt.Println("DONE.") }
這段代碼從邏輯上看合乎情理,但是是一種非常 投機取巧 的做法,即根據第 10 個 goroutine 的執行情況來 草率地 認為前面的 9 個 goroutine 都已經執行完畢。如果你將 `runtime.GOMAXPROCS(runtime.NumCPU())` 這句注釋掉,使用單核運行程式,則將得到你所預期的效果;但如果使用多核的情況下,這種做法就是 錯誤的goroutine 是相互獨立的,且在執行過程中可能由於各種原因導致其中幾個 goroutine 讓出時間片給 CPU 去執行其它 goroutine。所以,我們 不能夠依靠 第 10 個 goroutine 的執行結果來判斷程式的運行情況。

解決方案一:利用 chan 的緩衝機制

package main import (         "fmt"        "runtime") // 從 1 至 1 億迴圈疊加,並列印結果。 func print(c chan bool, n int) {         x := 0         for i := 1; i <= 100000000; i++ {                 x += i         }         fmt.Println(n, x)         c <- true}   func main() {     // 使用多核運行程式         runtime.GOMAXPROCS(runtime.NumCPU())         c := make(chan bool, 10)         for i := 0; i < 10; i++ {                 go print(c, i)         }         for i := 0; i < 10; i++ {                 <-c         }         fmt.Println("DONE.") }
解決方案二: 使用 sync 包的 WaitGroup
package main import (     "fmt"    "runtime"    "sync") // 從 1 至 1 億迴圈疊加,並列印結果。 func print(wg *sync.WaitGroup, n int) {     x := 0     for i := 1; i <= 100000000; i++ {         x += i     }     fmt.Println(n, x)     // 標識一次任務完成     wg.Done() }   func main() {     // 使用多核運行程式     runtime.GOMAXPROCS(runtime.NumCPU())     // 建立等待組     wg := sync.WaitGroup{}     // 設定需要等待的對象個數     wg.Add(10)     for i := 0; i < 10; i++ {         go print(&wg, i)     }     // 等待所有任務完成     wg.Wait()     fmt.Println("DONE.") }

7. golang http請求最佳化

//判斷url是否有效//沒有http://開頭,就加上http://if !strings.HasPrefix(feed, "http") {    feed = "http://" + feed}//判斷url是否合理host, err := url.ParseRequestURI(feed)if err != nil {}//判斷是否能解析到對應的host記錄_, err = net.LookupIP(host.Host)if err != nil {}//向主機請求資料client := &http.Client{    Transport: &http.Transport{        Dial: func(netw, addr string) (net.Conn, error) {            deadline := time.Now().Add(10 * time.Second)            c, err := net.DialTimeout(netw, addr, 5*time.Second) //連線逾時時間            if err != nil {                return nil, err            }            c.SetDeadline(deadline)            return c, nil        },    },}req, err := http.NewRequest("GET", feed, nil)if err != nil {}//資料轉送壓縮//告訴主機 支援gzip 資料請求回來後 ungzipreq.Header.Set("User-Agent", "Mozilla/5.0 (compatible; UJCspider/0.1; +http://ujiecao.com/help)")req.Header.Set("Accept-Encoding", "gzip")resp, err := client.Do(req)if err != nil {}defer resp.Body.Close()var reader io.ReadCloserswitch resp.Header.Get("Content-Encoding") {case "gzip":    reader, _ = gzip.NewReader(resp.Body)    defer reader.Close()default:    reader = resp.Body}


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.