个人犯的一个golang routine错误

认识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/

时间: 2024-11-05 11:46:14

个人犯的一个golang routine错误的相关文章

开源一个golang小程序商城后台(moshopserver)

开源一个golang小程序商城后台(moshopserver) golang和c/c++比起来是一门新的语言,一直想学,网上搜集了一些资料,有些人说很容易上手,确实是这样,和C/C++比起来,少了很多乱七八糟的语法.学一门新的语言,最好的方法就是动手写一些东西,最近小程序也比较火,也想学一下,网络上搜索的一些开源项目,基本上没有golang实现的,大部分都是nodejs和java写的,那么我就来实现一个golang版的吧,一石二鸟. 开发小程序前后端都需要开发,自己的前端经验很少,搜索了一些开源

苹果平板的按键和电源接线放在一个地方是一个最大的错误

苹果平板的按键和电源接线放在一个地方是一个最大的错误,为什么?我崽使用了一年,电源线接触不良了,要按着按键才能充电.这说明焊锡有松脱问题了.要么电源插口放在别处,不与按键放一处,要么采用感应式的软按键---和案桌的一样,最好是两个方案并用.这维修很复杂的.就拆都够费劲的了,还有焊锡.暗脱的焊锡更烦,还得测电阻. 联想YOGA Tablet 8在这方面考虑比较好.如何再冗余一个专用圆口充电接口就更漂亮了,毕竟充电接口是用的最频繁的了.---两三千的用一年就接触不良的使用体验绝对是一个很差的体验.

关于启动 SecureCRT 遇到一个致命的错误且必须关闭

--------------------------SecureCRT---------------------------SecureCRT 遇到一个致命的错误且必须关闭. 一个崩溃转储文件已创建于: C:\Users\Administrator\AppData\Roaming\SecureCRT.dmp 请提交一个 bug 报告给 VanDyke Software, Inc. 的技术支持,, 使用以下的 URL 地址: 你将收到如何发送崩溃转储文件的说明. (此信息的内容可以通过 CTRL+

5年前的今天,一个小小的部署错误,让美股最大交易商坠入深渊

郑昀(订阅号:老兵笔记) 创建于2017/7/29 最后更新于2017/7/31 提纲: 骑士资本集团的大麻烦 毁于冲马桶设计的潜艇 域名轻易被劫持 不可能被攻破的金库被盗 0x01 骑士资本集团的大麻烦 5年前的今天,因为一个小小的部署错误, 仅仅 45 分钟, 一家美国股市最大的交易商.纽交所以及纳斯达克的大庄家变得一钱不值. 2012年的时候,骑士资本是美国股票市场最大的经纪商,分别占有纽交所和纳斯达克 17% 的市场份额. 骑士资本的电子贸易部门管理的平均日交易量超过 33 亿股,交易额

关于 SecureCRT 遇到一个致命的错误且必须关闭。

今天因为公钥的原因下了一款 版本靠前的  secureCRT  但是 在回头使用以前的版本 ---------------------------SecureCRT---------------------------SecureCRT 遇到一个致命的错误且必须关闭. 一个崩溃转储文件已创建于: C:\Users\Administrator\AppData\Roaming\SecureCRT.dmp 请提交一个 bug 报告给 VanDyke Software, Inc. 的技术支持, 使用以下

又是一个愚蠢的错误,皆因.xml而起

   论java中的.xml到底有多坑?! 感觉自己都快哭了,再一次被.xml给坑了一下,这次坑的太狠了,一下子导致自己浪费了昨天一下午,一晚上,今天一上午和半个下午呀,中间的过程真的是乏善可陈呀,各种转折,各种离奇的错误,自己都崩溃了好多次,让我一一来诉说吧. 1.在springmvc分层结构中(分为mybatis层.service层.controller层)自己定义了一个定时器,定时器是定义在service的配置文件中的,文件如下: 1 <?xml version="1.0"

SecureCRT 遇到一个致命的错误且必须关闭

解决SecureCRT报错的问题 SercureCRT 报错内容: SecureCRT 遇到一个致命的错误且必须关闭. 一个崩溃转储文件已创建于: C:\Documents and Settings\Administrator\Application Data\SecureCRT.dmp 1.在网上查了一下,说是将该路径中VanDyke文件夹内的东西删除掉就可以了.回去删除后发现还是错误. 在regedit搜索 VanDyke, 一般有两个全部删除就可以了 2.继续查,在注册表中将HKEY_LO

Go_19: Golang 中错误与异常需要重新认识

如何进行错误处理,这是一个Go程序员之间,特别是一些新的Go程序员,会经常讨论的问题.讨论到最后往往由于以下代码的多次出现而变成了抱怨. if err != nil { return err } 我们最近扫描了我们能找到的开源项目,这段代码只在一页或者两页中出现了一次,是不是比你想象的少很多.然而,必须到处写 if err != nuil的感觉依然存在 , 那一定是哪里出了问题,而且明显问题出在Go自己身上. 不幸的是,这是一个误解,而且很容易纠正.或许一个新的Go程序员想问 "怎么会只有一个错

[网络课摘抄]4.演示一个导致ora-01555错误的场景

1创建一个undo表空间 2查看当前undo配置 3更该默认undo表空间 4确认更改的配置 5创建一张测试表 6模拟批量操作 7 查询2分钟前的数据 从这里可以到当查询2分钟前的数据时候,系统报出ORA-01555错误,提示我们快照太老.导致这种错误出现的原因是因为由于设置的回滚段太小且回滚段循环使用,在查询之前某个时刻数据状态时需要从回滚段中勾勒出数据的前映像,由于保存数据前映像的回滚段已经被覆盖,导致查询无法实现一致性读,查询失败,报出ORA-01555错误.