Golang append是并发安全的吗

首发于微信公众号:【码农在新加坡】,欢迎关注。

个人博客网站:Golang append是并发安全的吗

背景

最近开发的时候写了下面这段类似的代码。

func TestAppend() (result []int) {
   
	var wg sync.WaitGroup
	for i := 0; i < 100; i++ {
   
		v := i
		wg.Add(1)
		go func() {
   
			// other logic
			result = append(result, v)
			wg.Done()
		}()
	}

	wg.Wait()
	//fmt.Printf("%v\n", len(result))
	return result
}

就像这样,然后顺利通过测试到达生产环境。然后就出问题了。

预期情况下,len(result) = 100, 但是大多数情况下,这个数据会<=100。因为append这个函数不是并发安全的。也就是不能在多个goroutine里面对同一个slice使用append进行追加。

那么问题出在哪呢?

我们都知道slice是对数组一个连续片段的引用,当slice长度增加的时候,可能底层的数组会被换掉。在换底层数组之前,切片同时被多个goroutine拿到,并执行append操作。那么很多goroutine的append结果会被覆盖,导致n个gouroutine append后,长度小于n。

你以为这是最坏的影响吗,并不是的。数据出bug了是小事,最坏的影响是直接服务直接panic
append咋还导致服务panic呢?且往下看。

原因分析

要分析这个原因,我们需要了解slice的底层结构。

type slice struct {
   
    array unsafe.Pointer
    len   int
    cap   int

你可能感兴趣的:(golang,golang,开发语言,后端)