暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Golang并发编程中的常用技巧

政采云运维团队 2021-10-16
1000

本文将用简洁易懂的语言,为大家提供一些在golang语言中,那些能够"饮鸩止渴"的提高代码质量的并发编程技巧。


goroutine

  1. 如果你的goroutine在另一个goroutine返回之前无法取得进展,这种场景下应该只用一个goroutine完成工作。这样能消除将结果从goroutine返回到它的启动器所需要的chan操作。下面是一个错误的示范。

  2. 如果你不知道一个goroutine什么时候结束,那就不要启动它。比如说分别用goroutine运行了两个web服务,并且你希望这两个web服务要么都运行,要么都不运行,那你就必须要知道这个goroutine的状态,并且有主动让他退出的手段。

  1. goroutine的pianc会引发整个进程的退出,可以这样去捕捉。

  2. 启动goroutine的应该是包的调用者,所以包的设计者应该尽可能地把是否并发的控制逻辑交出去。反过来说如果调用者都不知道我调用一次就会开启多少个goroutine,这是比较危险的行为。

  1. 服务内不可恢复的错误,可以传递出一个信号,对服务进行优雅停止。

  2. 利用context包提供的方法可以轻松实现超时控制。


标准库sync包

  1. 最晚加锁,最早释放。任何语言中都要遵循这个原则,减少锁住的时间,能够充分利用硬件资源,不再赘述。

  2. 能够使用原子操作的场景,就要避免加锁,因为加锁涉及到更多的上下文切换。附上一张性能测试对比图。

  1. 读多写少的并发场景下灵活运用写时复制(copy on write)可以无锁访问共享数据。具体思路是写操作时,全量复制一个老的对象,写完之后再使用原子操作替换掉旧的数据。

  2. 使用sync.Pool 保存临时对象, 可以减少内存分配和GC的压力。


channel

  1. 一定要交给发送者来关闭channel,因为向关闭的channel发送数据会painc。

  2. 利用channel实现一个pipeline, 这种方法可以很容易的把代码安单一职责原则进行拆分。

  1. 扇入/扇出(fan-in/fan-out) 多个channel被同一个函数消费, 并汇总到一个chennel/多个函数消费同一个channel。



标准库context包

  1. context 主要用来在 goroutine 之间传递上下文信息,包括:取消信号、超时时间、截止时间、k-v 等。

  2. context 一定要显示传递, 不要包在结构体里。

  1. 通常要放在参数的第一个。

  2. 如果你不知道要用哪个context, 请用标准库提供的context.TODO()。

  1. 用来传递共享数据

  2. 用来取消goroutine

  1. ctx只应该传递信号,所以不要把你的业务数据放进去。

errgroup

当我们把一个复杂任务分解为多个,并委派到不同的goroutine去执行,并把结果汇总。errgroup十分适合在这种场景下,管理goroutine。

  1. 这个包提供了完善的管理并行goroutine的方法,包括错误处理或者优雅降级,context的局部传播或者取消.

Referneces

  1. https://coolshell.cn/articles/21228.html

  2. https://golang.org/doc/effective_go

文章转载自政采云运维团队,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论