zoukankan      html  css  js  c++  java
  • 个人犯的一个golang routine错误

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

    认识golang也不少时间了,也做过几个项目。最近发现之前用golang写的一个服务,内存涨得比较快,一直没找出来原因来。今天把疑惑发到群里,经过golang学习班的童鞋的指点,发现我一个常用的错误。

    在不少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)
    }

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

    其实可以通过这个去实现。

    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来处理每个用户请求。

    比如,有个全局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/

  • 相关阅读:
    Lucene学习总结之一:全文检索的基本原理
    Solr学习和总结(线下1)
    HBase学习系列
    Hadoop家族系列文章
    SQL on Hadoop系统的最新进展(1)
    【转】redis数据库入门教程(全面详细)+面试问题
    Redis(1.3)Redis的基本特性(事务、多数据库)
    (5.15)mysql高可用系列——mysql mha实践
    Redis(1.2)Redis的数据结构与基本操作
    mysql函数使用报错
  • 原文地址:https://www.cnblogs.com/nonsuch/p/4222838.html
Copyright © 2011-2022 走看看