# append() 并发安全问题

# 由来:

今天在编程过程中遇到这样一个问题,并发把数据写入到切片中。

var posts []int

func hello(i int) {
	defer wg.Done() // goroutine结束就登记-1
	posts = append(posts, i)
}
func main() {
	for i := 0; i < 10; i++ {
		wg.Add(1) // 启动一个goroutine就登记+1
		go hello(i)
	}
	wg.Wait() // 等待所有登记的goroutine都结束
	fmt.Println(posts)
}

结果输出各不相同:

//输出go run main.go
[5 4 6 1 0 2 9 7 8]go run main.go
[0 9 4]go run main.go
[0 3 1 2 5 4 6 7 9 8]go run main.go
[0 8 7 9]

# 原因:

当A和B两个协程运行append的时候同时发现posts[1]这个位置是空的,他们就都会把自己的值放在这个位置,这样他们两个的值就会覆盖,造成数据丢失。

# 解决:

最简单的方式就是用锁,贴一个例子

var posts []int
var mutex sync.Mutex
var wg    sync.WaitGroup

func hello(i int) {
	defer wg.Done() // goroutine结束就登记-1
	mutex.Lock()
	posts = append(posts, i)
	mutex.Unlock()
}
func main() {
	for i := 0; i < 10; i++ {
		wg.Add(1) // 启动一个goroutine就登记+1
		go hello(i)
	}
	wg.Wait() // 等待所有登记的goroutine都结束
	fmt.Println(posts)
}