golang append的併發問題

先看一段代碼安全

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	s := make([]int, 0, 1000)

	for i := 0; i < 1000; i++ {
		v := i
		wg.Add(1)
		go func() {
			s = append(s, v)
			wg.Done()
		}()
	}

	wg.Wait()
	fmt.Printf("%v\n", len(s))
}

結果架構

第一次:928
第二次:945
第三次:986
……

多運行幾回你就會發現,slice長度並非1000,而是不停的在變,爲何呢?(若是這個代碼你沒法重現,你能夠嘗試將1000改成更大的數字)併發

由於append並非併發安全的。app

咱們舉一個簡單例子,好比,當A和B兩個協程運行append的時候同時發現s[1]這個位置是空的,他們就都會把本身的值放在這個位置,這樣他們兩個的值就會覆蓋,形成數據丟失。code

那該怎麼寫?最簡單的方式就是用鎖,貼一個例子協程

package main

import (
	"fmt"
	"sync"
)

func main() {
	var (
		wg    sync.WaitGroup
		mutex sync.Mutex
	)

	s := make([]int, 0, 1000)

	for i := 0; i < 1000; i++ {
		v := i
		wg.Add(1)
		go func() {
			mutex.Lock()
			s = append(s, v)
			mutex.Unlock()
			wg.Done()
		}()
	}

	wg.Wait()
	fmt.Printf("%v\n", len(s))
}

運行一下這個例子就會發現,s的長度老是1000。it

更多架構、PHP、GO相關踩坑實踐技巧請關注個人公衆號:PHP架構師import

相關文章
相關標籤/搜索