golang学习交流

golang goroutine

2020-12-17  本文已影响0人  Stevennnmmm

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

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

goroutine

第一个文章不得不说一下这个明星关键字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无法管控。

解决办法:

3.管控goroutine执行超时

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

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

4.野生goroutine 尽量少用

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

当然这种情况也要分的

func main() {
    Go(func() {
        
    })
}

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

        f()
    }()
}
上一篇 下一篇

猜你喜欢

热点阅读