Go语言中文网,致力于每日分享编码、开源等知识,欢迎关注我,会有意想不到的收获!
问题
![5ee761dadc09678c96bb6e5241d44164.png](https://i-blog.csdnimg.cn/blog_migrate/5d9e708c2627cc79de64278987b7900e.jpeg)
在这里,假设 userCount 是一个外部传入的参数(不可预测,有可能值非常大),有人会全部丢进去循环。想着全部都并发 goroutine 去同时做某一件事。觉得这样子会效率会更高,对不对!
那么,你觉得这里有没有什么问题?
噩梦般的开始
当然,在特定场景下,问题可大了。因为在本文被丢进去同时并发的可是一个极端值。我们可以一起观察下图的指标分析,看看情况有多 “崩溃”。下图是上述代码的表现:
输出结果
...go func: 5839go func: 5840go func: 5841go func: 5842go func: 5915go func: 5524go func: 5916go func: 8209go func: 8264signal: killed
如果你自己执行过代码,在 “输出结果” 上你会遇到如下问题:
- 系统资源占用率不断上涨
- 输出一定数量后:控制台就不再刷新输出最新的值了
- 信号量:signal: killed
系统负载
![4d7add6918f14170ae6c89a75fd01b92.png](https://i-blog.csdnimg.cn/blog_migrate/a6b505e6ba113e1c67ef902d22c321b2.jpeg)
CPU
![a11dcfb1875a32c6d68d0a094f6acd67.png](https://i-blog.csdnimg.cn/blog_migrate/093a4ca6c607d9a8034aff60acfa030a.jpeg)
短时间内系统负载暴增
虚拟内存
![7e570e0799a684ca23549cb1d05776e9.png](https://i-blog.csdnimg.cn/blog_migrate/19949f6a31dc4519e8bd52880139c125.jpeg)
短时间内占用的虚拟内存暴增
top
PID COMMAND %CPU TIME #TH #WQ #PORT MEM PURG CMPRS PGRP PPID STATE BOOSTS...73414 test 100.2 01:59.50 9/1 0 18 6801M+ 0B 114G+ 73403 73403 running *0[1]
小结
如果仔细看过监控工具的示意图,就可以知道其实我间隔的执行了两次,能看到系统间的使用率幅度非常大。当进程被杀掉后,整体又恢复为正常值
在这里,我们回到主题,就是在不控制并发的 goroutine 数量 会发生什么问题?大致如下:
- CPU 使用率浮动上涨
- Memory 占用不断上涨。也可以看看 CMPRS,它表示进程的压缩数据的字节数。已经到达 114G+ 了
- 主进程崩溃(被杀掉了)
简单来说,“崩溃” 的原因就是对系统资源的占用过大。常见的比如:打开文件数(too many files open)、内存占用等等
危害
对该台服务器产生非常大的影响,影响自身及相关联的应用。很有可能导致不可用或响应缓慢,另外启动了复数 “失控” 的 goroutine,导致程序流转混乱
解决方案
在前面花了大量篇幅,渲染了在存在大量并发 goroutine 数量时,不控制的话会出现 “严重” 的问题,接下来一起思考下解决方案。如下:
- 控制/限制 goroutine 同时并发运行的数量
- 改变应用程序的逻辑写法(避免大规模的使用系统资源和等待)
- 调整服务的硬件配置、最大打开数、内存等阈值
控制 goroutine 并发数量
接下来正式的开始解决这个问题,希望你认真阅读的同时加以思考,因为这个问题在实际项目中真的是太常见了!
问题已经抛出来了,你需要做的是想想有什么办法解决这个问题。建议你自行思考一下技术方案。再接着往下看 :-)
尝试 chan
func main() {userCount := 10ch := make(chan bool, 2)for i := 0; i < userCount; i++ {ch