注:本文已发布超过一年,请注意您所使用工具的相关版本是否适用
本系列为 Go 进阶训练营 笔记,访问 博客: Go进阶训练营, 即可查看当前更新进度,部分文章篇幅较长,使用 PC 大屏浏览体验更佳。
接下来会一共会有 12 - 15 篇文章讲解 Go 并发编程,并发编程本身是一个挺大的话题,在第四周的两节课,毛老师花了将近 7 个小时讲解这些内容,我也结合自己的一些微不足道的经验,再加上一些大神们的文章,整理出了这一部分的笔记。
当然这里更多的是抛砖引玉的作用,更多的还是我们自己要有相关的意识避免踩坑,在各个坑的边缘反复横跳,可能我们有缘会在同一个坑中发现,咦,原来你也在这里 😄
请阅读下面这段代码,看看有什么问题?
为什么先从下面这段代码出发,是因为在之前的经验里面我们写了大量类似的代码,之前没有意识到这个问题,并且还因为这种代码出现过短暂的事故
1 | |
灵魂拷问来了,请问:
server 是在其他包里面,如果没有特殊说明,你知道这是一个异步调用么?main 函数当中最后在哪里空转干什么?会不会存在浪费?8081 端口的服务?请把是否并发的选择权交给你的调用者,而不是自己就直接悄悄的用上了 goroutine
下面这次改动将两个函数是否并发操作的选择权留给了 main 函数
1 | |
一般情况下,不要让主进程成为一个旁观者,明明可以干活,但是最后使用了一个 select 在那儿空跑
感谢上一步将是否异步的选择权交给了我( main ),在旁边看着也怪尴尬的
1 | |
我们再做一些改造,使用 channel 来控制,解释都写在代码注释里面了
1 | |
我们看一下返回结果,这个代码启动 5s 之后就会退出程序
1 | |
虽然我们已经经过了三轮优化,但是这里还是有一些需要注意的地方,可以思考一下怎么做
Shutdown 方法,但是我们其实并没有实现优雅退出,相信聪明的你可以完成这项工作。可以参考上一篇笔记:Go 错误处理最佳实践server 方法中我们并没有处理 panic 的逻辑,这里需要处理么?如果需要那该如何处理呢?再来看下面一个例子,这也是常常会用到的操作
1 | |
复用一下上面的 server 代码,我们经常会写出这种类似的代码
绝大部分的 goroutine 泄漏都是因为 goroutine 当中因为各种原因阻塞了,我们在外面也没有控制它退出的方式,所以就泄漏了,具体导致阻塞的常见原因会在接下来的 sync 包、channel 中讲到,这里就不过多赘述了
接下来我们验证一下是不是真的泄漏了
启动之后我们访问一下: http://localhost:8081/debug/pprof/goroutine?debug=1 查看当前的 goroutine 个数为 7
1 | |
然后我们再访问几次 http://localhost:8080/leak 可以发现 goroutine 增加到了 15 个,而且一直不会下降
1 | |
这个其实就是优雅退出的问题,我们可能启动了很多的 goroutine 去处理一些问题,但是服务退出的时候我们并没有考虑到就直接退出了。例如退出前日志没有 flush 到磁盘,我们的请求还没完全关闭,异步 worker 中还有 job 在执行等等。
我们也来看一个例子,假设现在有一个埋点服务,每次请求我们都会上报一些信息到埋点服务上
1 | |
我在发送了一次请求之后直接退出了,异步上报的逻辑根本没执行上
1 | |
这个有两种改法,一种是给 reporter 加上 shutdown 方法,类似 http 的 shutdown,等待所有的异步上报完成之后,我们再退出,另外一种是我们直接使用 一些 worker 来执行,在当然这个 worker 也要实现类似 shutdown 的方法。一般推荐后一种,因为这样可以避免请求量比较大时,创建大量 goroutine,当然如果请求量比较小,不会很大,用第一种也是可以的。
我们给一个第二种的简单实现,第一种可以参考 https://www.ardanlabs.com/blog/2019/04/concurrency-trap-2-incomplete-work.html
1 | |
然后在 main 函数中我们加上
1 | |
留一个思考题:我们在 reporter 的实现可能会导致 panic,你是否发现了呢?如何修改可以避免这种情况? 感谢评论区 @hddxds 的指出,我这里给出一个实现例子: [点击查看](https://github.com/mohuishou/Go-000/blob/main/Week03/blog/01_goroutine/07/reporter.go),可以看看是否和你想的一样? 如果你对为什么会出现 panic 或者为什么要这么实现感到困惑可以查看后面的这篇文章 [Go并发编程(十) 深入理解 Channel](https://lailin.xyz/post/go-training-week3-channel.html)
总结一下这一部分讲到的几个要点,这也是我们
注:本文已发布超过一年,请注意您所使用工具的相关版本是否适用
本系列为 Go 进阶训练营 笔记,访问 博客: Go进阶训练营, 即可查看当前更新进度,部分文章篇幅较长,使用 PC 大屏浏览体验更佳。
接下来会一共会有 12 - 15 篇文章讲解 Go 并发编程,并发编程本身是一个挺大的话题,在第四周的两节课,毛老师花了将近 7 个小时讲解这些内容,我也结合自己的一些微不足道的经验,再加上一些大神们的文章,整理出了这一部分的笔记。
当然这里更多的是抛砖引玉的作用,更多的还是我们自己要有相关的意识避免踩坑,在各个坑的边缘反复横跳,可能我们有缘会在同一个坑中发现,咦,原来你也在这里 😄
请阅读下面这段代码,看看有什么问题?
为什么先从下面这段代码出发,是因为在之前的经验里面我们写了大量类似的代码,之前没有意识到这个问题,并且还因为这种代码出现过短暂的事故
1 | |
灵魂拷问来了,请问:
server 是在其他包里面,如果没有特殊说明,你知道这是一个异步调用么?main 函数当中最后在哪里空转干什么?会不会存在浪费?8081 端口的服务?请把是否并发的选择权交给你的调用者,而不是自己就直接悄悄的用上了 goroutine
下面这次改动将两个函数是否并发操作的选择权留给了 main 函数
1 | |
一般情况下,不要让主进程成为一个旁观者,明明可以干活,但是最后使用了一个 select 在那儿空跑
感谢上一步将是否异步的选择权交给了我( main ),在旁边看着也怪尴尬的
1 | |
我们再做一些改造,使用 channel 来控制,解释都写在代码注释里面了
1 | |
我们看一下返回结果,这个代码启动 5s 之后就会退出程序
1 | |
虽然我们已经经过了三轮优化,但是这里还是有一些需要注意的地方,可以思考一下怎么做
Shutdown 方法,但是我们其实并没有实现优雅退出,相信聪明的你可以完成这项工作。可以参考上一篇笔记:Go 错误处理最佳实践server 方法中我们并没有处理 panic 的逻辑,这里需要处理么?如果需要那该如何处理呢?再来看下面一个例子,这也是常常会用到的操作
1 | |
复用一下上面的 server 代码,我们经常会写出这种类似的代码
绝大部分的 goroutine 泄漏都是因为 goroutine 当中因为各种原因阻塞了,我们在外面也没有控制它退出的方式,所以就泄漏了,具体导致阻塞的常见原因会在接下来的 sync 包、channel 中讲到,这里就不过多赘述了
接下来我们验证一下是不是真的泄漏了
启动之后我们访问一下: http://localhost:8081/debug/pprof/goroutine?debug=1 查看当前的 goroutine 个数为 7
1 | |
然后我们再访问几次 http://localhost:8080/leak 可以发现 goroutine 增加到了 15 个,而且一直不会下降
1 | |
这个其实就是优雅退出的问题,我们可能启动了很多的 goroutine 去处理一些问题,但是服务退出的时候我们并没有考虑到就直接退出了。例如退出前日志没有 flush 到磁盘,我们的请求还没完全关闭,异步 worker 中还有 job 在执行等等。
我们也来看一个例子,假设现在有一个埋点服务,每次请求我们都会上报一些信息到埋点服务上
1 | |
我在发送了一次请求之后直接退出了,异步上报的逻辑根本没执行上
1 | |
这个有两种改法,一种是给 reporter 加上 shutdown 方法,类似 http 的 shutdown,等待所有的异步上报完成之后,我们再退出,另外一种是我们直接使用 一些 worker 来执行,在当然这个 worker 也要实现类似 shutdown 的方法。一般推荐后一种,因为这样可以避免请求量比较大时,创建大量 goroutine,当然如果请求量比较小,不会很大,用第一种也是可以的。
我们给一个第二种的简单实现,第一种可以参考 https://www.ardanlabs.com/blog/2019/04/concurrency-trap-2-incomplete-work.html
1 | |
然后在 main 函数中我们加上
1 | |
留一个思考题:我们在 reporter 的实现可能会导致 panic,你是否发现了呢?如何修改可以避免这种情况? 感谢评论区 @hddxds 的指出,我这里给出一个实现例子: [点击查看](https://github.com/mohuishou/Go-000/blob/main/Week03/blog/01_goroutine/07/reporter.go),可以看看是否和你想的一样? 如果你对为什么会出现 panic 或者为什么要这么实现感到困惑可以查看后面的这篇文章 [Go并发编程(十) 深入理解 Channel](https://lailin.xyz/post/go-training-week3-channel.html)
总结一下这一部分讲到的几个要点,这也是我们