最近由于 并发性能优化复盘 开始看并发编程相关的书籍,希望借着书把并发相关的内容给摸清。现在看的差不多了,可以写篇学习笔记记录下。

首先,并发不是并行这个不用解释了。

要用到并发,主要有两种模式:

  • Worker Pool: 工作池模式;
  • Pipeline: 管道模式;

用 Worker Pool 模式,可以手写协程约束并发数或者用 go ants pool 协程池学习笔记 等库来实现限制并发数。

用 Pipeline 模式,可以解耦协程,防止依赖。其中,无缓冲的通道适用同步模式,有缓冲通道适用一定程度的异步处理。

不仅限于此还有 fan-out(扇出)和 fan-in(扇入)模式。扇出个人觉得使用起来要注意场景,防止无限创建协程导致CPU/内存资源消耗。go net/http 用的就是扇出模式,如果无限制请求可能会导致内存泄露等问题。

书中也提到了 or-done-channeltee-channel 等模式,具体使用时可以结合业务场景合理选择需要用的模式。

当然仅仅会创协程,并不代表会用协程。除了常用的设计模式,还要关注协程的生命周期管理。

协程的超时,取消,退出是如何做的,这里就需要 context/sync 包。

协程的错误处理是怎么做的,我们可以用 errgroup 包实现协程的错误处理,errgroup 包也支持取消协程。

但是 errgroup 包是有一个协程有问题就上报,如果我们需要等所有协程运行完在处理错误,则需要自己实现相应的错误处理逻辑。

在书中有一种场景需要描述下的是:限速。

虽然后端协程可以并发处理请求,但是如果不加节制的并发请求,可能导致协程处理不过来/阻塞/不可用甚至 OOM 等情况。

为了防止这种情况发生,在协程处理前加上限速就很有必要了。速率限制 一节就给我们描述了这样一种场景。

go-zero 中内置了速率限制(限流)和熔断的处理逻辑,非常棒。后面我们可以花点时间着重看下限流和熔断机制。

现在我们会写协程的一些模式和如何管理协程,那么我们如何测试呢? 在写代码时如何快速诊断呢?毕竟没有人想在生产环境上被一堆人盯着干活吧 😂

我们可以用 go run -racepprof 工具来诊断。 go run -race 在运行程序的时候查看是否有竞态,这个主要是判断是否有锁冲突。 pprof 是非常厉害的诊断工具,日常写代码时加上 pprof 是一个非常好的习惯。笔者曾借助 pprof 优化了一个性能问题。

最后,在写代码时要注意用并发的思维去考虑,笔者曾经面试了一家公司,用的一个非常标准的算法,面试官说可以用并发吗?然后给我描述了下并发思路,那一刻有种醍醐灌顶的感觉,还是要活学活用哇。

参考文章