我的犯的一个golang routine错误

这个其实不是错误,2个写法没有区别。-2015.11.22golang

 

认识golang也很多时间了,也作过几个项目。最近发现以前用golang写的一个服务,内存涨得比较快,一直没找出来缘由来。今天把疑惑发到群里,通过golang学习班的童鞋的指点,发现我一个经常使用的错误。json

 

在很多golang入门的文章上,用并发的例子通常是这样写的;服务器

package main

import (
    "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) }

我以前的项目,也一直是这样写。今天和群里的讨论了下,才发觉,这个写法实际上是比较丑陋的。session

其实能够经过这个去实现。并发

package main

import (
    "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来处理每一个用户请求。ui

好比,有个全局Map变量: map[int]list,  每一个请求建立一个巍峨惟一的随机数或者sessionId, 而后每一个go rouine处理完后,根据sessionid去查找对应的list, 插入数据。url

能够利用list来实现异步队列的机制,避免锁。

因此特意在这记录下来,固然各位新人的参考。

 

附上国外的一篇文章:  http://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/