golang goroutine

其实用go也用了一段时间,我是看视频入门的,然后去买书,反正来来回回用了一年多的时间,很多点知道怎么用,相关知识也能答上来,但是始终有种感觉就是这样会不会有问题,这个文档就用来记录我复盘golang的学习过程的。

当然基础容器这些我是了解得够多了,所以主要这个文集停留于用的层面,就是关于go的工程化,毕竟我们的代码不单单是给我们自己看的,工程化代码是很有必要的。所以文集的线索会从官方文档到翻译再加上一些辅助资料和实践出真知的例子来说明相关关键字用法,当然在这个过程中也会发生很多错误,如果你看到了,或者你有什么疑问也可以在文章下面评论,我看到就会及时回复的。

goroutine

第一个文章不得不说一下这个明星关键字goroutine。这个小学生都会写的关键字,我们到底如何用它

  • 1.尽可能自己做事而不是交给goroutine
  • 2.当你不知道goroutine什么时候会关闭的时候就不要使用goroutine
  • 3.管理起goroutine的声明周期,开启一个goroutine请问一下自己
    1:goroutine什么时候会关闭
    2:怎么去主动关闭goroutine

goroutine的易错点

1.谨防goroutine泄露
When it comes to memory management, Go deals with many of the details for you. The Go compiler 
decides where values are located in memory using [escape analysis]
(https://www.ardanlabs.com/blog/2017/05/language-mechanics-on-escape-analysis.html). The runtime 
tracks and manages heap allocations through the use of the [garbage collector]
(https://blog.golang.org/ismmkeynote). Though it’s not impossible to create [memory leaks]
(https://en.wikipedia.org/wiki/Memory_leak) in your applications, the chances are greatly reduced.

A common type of memory leak is leaking Goroutines. If you start a Goroutine that you expect to 
eventually terminate but it never does then it has leaked. It lives for the lifetime of the application and 
any memory allocated for the Goroutine can’t be released. This is part of the reasoning behind the 
advice “[Never start a goroutine without knowing how it will stop]
(https://dave.cheney.net/2016/12/22/never-start-a-goroutine-without-knowing-how-it-will-stop)”.

翻译

并发编程允许开发人员使用多种执行路径来解决问题,并且经常用于提高性能。并发并不意味着这些多
个路径并行执行。这意味着这些路径是无序执行,而不是顺序执行。从历史上看,使用标准库或第三方
开发人员提供的库可以简化此类编程。

在Go中,语言和运行时内置了诸如Goroutine和通道之类的并发功能,以减少或消除对库的需求。这产生
了一种幻想,即在Go中编写并发程序很容易。在决定使用并发时,您必须谨慎,因为并发会带来一些独
特的副作用或陷阱(如果使用不正确)。如果不小心,这些陷阱会造成复杂性和令人讨厌的错误。

案例:

31 // leak is a buggy function. It launches a goroutine that
32 // blocks receiving from a channel. Nothing will ever be
33 // sent on that channel and the channel is never closed so
34 // that goroutine will be blocked forever.
35 func leak() {
36     ch := make(chan int)
37 
38     go func() {
39         val := <-ch
40         fmt.Println("We received a value:", val)
41     }()
42 }

此时我们的goroutine的状态称为泄露状态,我们无法管控,无法退出,我们要严防这类代码

2.控制goroutine退出

其实这里面有一定逻辑上的悖论,假设有个业务模型是这样的:用户注册成功,发送通知短信,发送通知邮件,这种业务叫做旁路业务,也就是主路业务不需要再次管理这种旁路业务,延不延迟其实都没太大所谓,用户不在乎,对于我们自身来说的话也没有太大的业务逻辑。那么就会出现这样的情况:

func main(){
    
    // 用户信息入库
    

    // 发送短信
    go  sendMsg("注册成功","1888888888")
    //todo other 
}

func sendMsg(msg string ,phoneNum int64)error{
  fmt.printf("给用户%v,发送了消息:%v\n",msg,phoneNum)
}

其实这是可以完成的,只是说这种代码非常危险,第一是对第三方平台不友好,第二是goroutine无法管控。

  • 假设我们的goroutine突然第三方响应变得很慢,每个接口需要1min响应,那么在我们内存中就有大量的goroutine,我们不能及时的取消这些goroutine,就导致很多有泄露的危险
  • 一般这种涉及到第三方的,对我们平台都有一定的限流,很多的请求就会直接报错误码,也就是会出现大量请求失败

解决办法:

  • 1.使用中间件消息队列,但是我举例的只是很小一个例子,其他不一定适用比如日志追踪,请求日志这类就肯定没必要丢到中间件又换个用户去处理
  • 2.使用生产消费模型,启动一个专门的goroutine去处理短信,然后使用一个channel传递,当我们通道塞满了后可以选择性的丢弃一半的buffer(当然丢弃指完全旁路,不想丢弃就加大消费者处理能力,比如多加一个goroutine)
3.管控goroutine执行超时

其实这里我相信实际开发的人员都知道一个坑点,就是在select的时候正在进行一项任务,另外一个case进入信号其实是会被阻塞的,在研发初期我一直以为它会直接取消。那我们应该怎么来正确使用context的超时,或者channel的关闭广播,实际context原理就是使用chan的广播。

划分业务:我们的业务其实细分起来是属于算力型和网络型

  • 算力型业务:最大应该也不超过100MS,算力型业务我们不应该执行超过这个标准,否则就应该划分函数了,而且算力型业务我们不能使用关闭它,只有等它完成才行
  • 网络型业务:中间件之间的调用,rpc调用都是通过网络模型来进行的,那么我们就可以比较容易的做到级联取消,在rpc调用的首参数就是可以添加超时控制,但是我们操控中间件:redis、mysql 好像没有context参数给我们使用,这是为什么呢?redis连接中实际上建立连接就有超时的参数设置,超时会报错,mysql则第一是使用连接池,不能直接关闭连接,第二是mysql本身有超时控制,需要在mysql端设置。所以我们常见的xorm,gorm都没有查询超时的策略,这种的话只有优化好我们的sql才行
4.野生goroutine 尽量少用

首先我们需要明确一点,在golang中没有类似php的那种框架兜底,也就是不论报什么错误都有一个函数给你兜底,不会导致程序宕机,那么其实这就是很恐怖的,又尤其在recover 不能捕获跨goroutine的错误,那么我们应该怎么来处理这个东西呢。
下面是我们采取的实例,简单的这样进行处理。

当然这种情况也要分的

  • 1.当go出去的是不可能报panic的,可以用我们封装的也可以不用,但是我建议还是用
  • 2.go出去的东西实际上又非常多逻辑 ,这种需要使用我们封装的
func main() {
    Go(func() {
        
    })
}

func Go(f func()){
    go func() {
        defer func() {
            if r:=recover();r!=nil{
                fmt.Println(r)
            }
        }()

        f()
    }()
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,498评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,668评论 3 406
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,857评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,305评论 1 303
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,308评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,747评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,078评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,080评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,649评论 1 327
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,644评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,760评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,352评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,076评论 3 341
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,490评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,651评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,353评论 3 383
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,828评论 2 367

推荐阅读更多精彩内容