這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
認識golang也不少時間了,也做過幾個項目。最近發現之前用golang寫的一個服務,記憶體漲得比較快,一直沒找出來原因來。今天把疑惑發到群裡,經過golang學習班的童鞋的指點,發現我一個常用的錯誤。
在不少golang入門的文章上,用並發的例子一般是這樣寫的;
package mainimport ( "fmt" "time")func main() { messages := make(chan int) go func() { time.Sleep(time.Second * 3) messages <- 1 }() go func() { time.Sleep(time.Second * 2) messages <- 2 }() go func() { time.Sleep(time.Second * 1) messages <- 3 }() go func() { for i := range messages { fmt.Println(i) } }() time.Sleep(time.Second * 5)}
我之前的項目,也一直是這樣寫。今天和群裡的討論了下,才發覺,這個寫法其實是比較醜陋的。
其實可以通過這個去實現。
package mainimport ( "fmt" "io/ioutil" "log" "net/http" "sync")func main() { urls := []string{ "http://www.reddit.com/r/aww.json", "http://www.reddit.com/r/funny.json", "http://www.reddit.com/r/programming.json", } jsonResponses := make(chan string) var wg sync.WaitGroup wg.Add(len(urls)) for _, url := range urls { go func(url string) { defer wg.Done() res, err := http.Get(url) if err != nil { log.Fatal(err) } else { defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { log.Fatal(err) } else { jsonResponses <- string(body) } } }(url) } go func() { for response := range jsonResponses { fmt.Println(response) } }() wg.Wait()}
這個更簡單,而且也更方便使用。效能方面,應該比chan要好點。
我之前的一個案例是,client發一個http request過來, 伺服器收到請求,然後同時開N個go routine去處理,然後每個處理完成後,通過chan 進行傳遞給主線程,主線程判斷chan的是否接收完成所有的請求,然後再響應。
就是用的第一種方法。
今天根據群裡面體的建議,重構了下。使用list來處理每個使用者請求。
比如,有個全域Map變數: map[int]list, 每個請求建立一個巍峨唯一的隨機數或者sessionId, 然後每個go rouine處理完後,根據sessionid去尋找對應的list, 插入資料。
可以利用list來實現非同步隊列的機制,避免鎖。
所以特地在這記錄下來,當然各位新人的參考。
附上國外的一篇文章: http://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/