Golang中Channel阻塞还是不阻塞?看我如何踩坑

107 阅读2分钟

上篇文章我意气风发封装了无限Channel,马上被新的需求打脸😭

新需求如下

  • 根据回传的数据进行反序列化,dump出图片并且生成视频转码之后上传到云端
    • 痛点:之前全量的数据很多,需要尽快生成完
      • 增量请求非常集中

第一次尝试

  • 请求来了之后将数据写入Redis,利用List数据类型实现一个消息队列,我们的处理Channel从Redis中读数据(Channel数量根据业务情况自行定义)
  • 在一个Channel里面完成下载,dump出图片并且生成视频转码之后上传到云端

Channel处理1.png

结果执行任务发现速度达不到我们的预期

  • 分析发现:因为使用下载使用内网,速度很快,视频生成、转码等比较慢
    • 如果我们开了十个Channel,可能十个Channel都在下载,利用的是IO资源,十个Channel都在转码等操作,利用的是CPU资源,如果都在IO资源,那CPU资源没有Channel在利用,如果都在CPU资源,那么IO资源没有利用

Channel处理2.png

优化方法

  • 改成专门负责下载的Channel、专门负责视频生成的Channel,这样可以将CPU资源和IO资源都充分利用

第二次:优化 (踩坑

  • 让下载Channel、视频生成Channel并行执行,使资源全部被利用

Channel处理3.png

  • 因为我使用是上个文章封装的无限Channel,并不会阻塞,但是下载的速度大于视频生成的速度,只有在视频生成之后才会将本地的下载的文件删除
  • 下载Channel完成下载任务的时候就发消息给视频生成Channel,视频生成Channel完成之后将本地文件删除,并不会有阻塞

这就导致了下载不会阻塞,但是处理比较慢,一段时间之后磁盘就会满了

第三次:完善

  • 无限Channel并不适合这个场景,因为下载的文件比较大,处理比较慢,会造成磁盘爆满的情况
  • 所以最后改成了阻塞式,具体的数量需要根据具体业务来定
  • 改成阻塞式的话不会出现磁盘爆满的问题,同时根据具体任务和CPU资源以及IO资源来决定数量,尽量利用好资源

总结

  • 并不是所有业务场景都可以使用无限Channel,这次算是狠狠踩坑了,并且在业务中,学会怎么尽量利用好资源,IO资源和CPU资源尽量得到充分利用
  • 阻塞Channel和非阻塞Channel的业务场景不一样,用好是利剑,没用好自损八百😭