2

正确规避常见的 Go 并发陷阱

 2 years ago
source link: http://blueskykong.com/2020/12/23/go-concurrency/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

作为一门并发性能优越的语言,Go虽然降低了协程并发开发的难度,但也存在一些并发陷阱,这就需要我们在开发时额外注意。

我们再来介绍与Go 并发相关的几个小技巧,帮助你规避 Go 并发开发的一些陷阱。

闭包传递参数的问题

首先是循环并发时闭包传递参数的问题,如下错误例子所示:

func main()  {
for i := 0 ; i < 5 ; i++{
go func() {
fmt.Println("current i is ", i)
}()
}
time.Sleep(time.Second)
}

这段代码极有可能的输出为:

current i is 5
current i is 5
current i is 5
current i is 5
current i is 5

这是因为 i 使用的地址空间在循环中被复用,在 goroutine 执行时,i 的值可能在被主 goroutine 修改,而此时其他 goroutine 也在读取使用,从而导致了并发错误。针对这种错误可以通过复制拷贝或者传参拷贝的方式规避,如下所示:

func main()  {
for i := 0 ; i < 5 ; i++{
go func(v int) {
fmt.Println("current i is", v)
}(i)
}
time.Sleep(time.Second)
}

panic 异常

上一篇介绍 panic 时我们了解到 panic 异常的出现会导致 Go 程序的崩溃。但其实即使 panic 是出现在其他启动的子 goroutine 中,也会导致 Go 程序的崩溃退出,同时 panic 只能捕获 goroutine 自身的异常,因此对于每个启动的 goroutine,都需要在入口处捕获 panic,并尝试打印堆栈信息并进行异常处理,从而避免子 goroutine 的 panic 导致整个程序的崩溃退出。如下面的例子所示:

func RecoverPanic() {
// 从 panic 中恢复并打印栈信息
if e := recover(); e != nil {
buf := make([]byte, 1024)
buf = buf[:runtime.Stack(buf, false)]
fmt.Printf("[PANIC]%v\n%s\n", e, buf)
}
}
func main() {
for i:= 0 ; i < 5 ; i++{
go func() {
// defer 注册 panic 捕获函数
defer RecoverPanic()
dothing()
}()
}
}

最后一个技巧是要善于结合使用 select、timer 和 context 进行超时控制。在 goroutine 中进行一些耗时较长的操作,最好都加上超时timer,在并发的时候也要传递 context,这样在取消的时候就不会有遗漏,进而达到回收 goroutine 的目的,避免内存泄漏的发生。如下面的例子所示,通过 select 同时监听任务和定时器状态,在定时器到达而任务未完成之时,提前结束任务,清理资源并返回。

select {
// do logic process
case msg <- input:
....
// has been canceled
case <-ctx.Done():
// ...资源清理
return
// 2 second timeout
case <-time.After(time.Second * 2)
// ...资源清理
return
default:
}

本文我们主要介绍了Go 中常见的一些并发开发技巧。笔者也只是抛砖引玉,提出了并发开发技巧的三个技巧,其实不仅仅是 Go 并发,大家在日常开发中需要注意总结各个方面的开发技巧。

Serverless 架构就不要服务器了?

微服务架构中使用 ELK 进行日志采集以及统一处理

没有 try-catch,该如何处理 Go 错误异常?

订阅最新文章,欢迎关注我的公众号


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK