golang 的goroutine池(线程池)

最近弄服务器的优化,在大量机器人面前,性能问题凸现出来。我是启用几台亚马孙服务器(一年免费用,每个区随便开一台,呵呵)去轰炸服务器了,然后内存暴涨,从几百兆渐渐的升到1个G,然后2个G,接着3个G。可怜本人的服务器也就3个G,当超越3G的时候,有些服务器进程就被OOM了。

一开始我觉得,是否人数太多,消息量太大导致的?然后用一些性能检测工具pprof之类,很多都指向protobuf(本人用的是Google的protobuf做网络协议的)。然后,向写go-protobuf的提了一个issue,用极其烂的英语说goproto内存泄露啊,有没有办法解决一下?于是他们的回答说,我提的问题,没有反应出内存泄露,只是内存不停的申请。不过也确实,这东西内存泄露,应该是不可能的,毕竟是gc语言。难道是某些东西把内存占着不释放导致?

想到这里我突然想起来了,goroutine这东西其实挺耗内存的(传说),于是乎,是否从这方面下手?原来我是每个客户端都会分配一个session,来维护连接的了。然后每个session会启动3个goroutine,一是用来读取消息,一个是用来发送消息,还有一个是用来检测生命周期的。当大量客户端连接时,那goroutine就是3倍客户端的数量啊。

golang号称可以百万级别并发,但goroutine也不应该无限制的创建吧,毕竟每次都向系统申请内存,系统内存总有耗尽的一天吧。那有没有一个池一样的东西,可以让goroutine可以重用,而不需要不节制的创建呢?

我们知道c#在.net 4以上有一个所谓Task的接口,它是用线程池的。 线程池目的就是线程可以重用,goroutine其实比线程轻量级,但问题是golang只是给了我们一个keyword——go,然后就没有然后了。咋办?

那我也只能再次各种Google以及百度了。确实,goroutine池一搜一大堆,看来我是孤陋寡闻了,于是满心高兴的去学习(抄代码)。但看上去都感觉颠覆我的理念的感觉,说白的就是越看越懵逼。

在偶然的机会上看到一篇文章,连接如下:https://mp.weixin.qq.com/s/aoWQSxrXXZUtJh48tmqMkA

蹲厕所看了半个小时,终于明白了。上面代码很清楚了,我就不贴了。我说说我的体会吧。goroutine池,跟对象池不一样。对象池是对象用完丢进池中,以便重用,那么池一开始是没用东西的。但goroutine池则不一样,因为它是不可控制的,不想c#线程一样,返回一个地址,可以随便关闭什么的,也不能像对象那样,先是无,然后创建,用完就放池里面。它创建后,如果逻辑完了,它就消亡了,因此必须一直维持这个goroutine!那么,这池就是这样了,一开始先开着n个goroutine。但一开始没逻辑执行啊,怎么办,那就让它们阻塞!用channel!那么怎么执行逻辑?那就是用接口!当阻塞的goroutine塞入一个东西,channel取出来,那么就可以工作了。逻辑就是调一个通用的函数!

那么,池的作用就显示出来了。我把session的三个需要用到goroutine的逻辑,封装成一个接口函数,那么,goroutine总量就降了很多,内存也降下去了。

不过上面文章的池有一个问题,就是当任务数量远远少于goroutine数量时,有可能会瞬间重复调用n次。我于是加了标志位,当某一任务在执行时,就不让他再进入工作了。那么保证它只能工作一次了。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值