Golang競爭狀態

來源:互聯網
上載者:User

看一段代碼:

package mainimport ("fmt""runtime""sync")var (counter intwg sync.WaitGroup)func main() {wg.Add(2)go incCounter(1)go incCounter(2)wg.Wait()fmt.Println("Final Counter:", counter)}func incCounter(id int) {defer wg.Done()for count := 0; count < 2; count++ {value := idruntime.Gosched()value++counter = value}}

goroutine執行的是副本值,然後將副本值寫入counter,所以在切換goroutine時,goroutine中的值會覆蓋counter。其中Gosched函數是runtime包中用於將goroutine從當前線程退出,給其它goroutine啟動並執行機會。這段代碼執行下來理論上應該是存在競爭狀態的,對於counter這個變數,在兩個goroutine的切換下,一共加了4次,但是由於每次切換後進入隊列的並不是真的這個值,而是一個副本,結果輸出應該為2。

事實貌似是這樣。。。貌似有點小問題。。。

檢測競爭狀態,再把這個gosched函數注釋,然後重新檢測競爭狀態,先後編譯執行得到的是:

為什麼會出現這個情況呢?Final Counter: 3

==================WARNING: DATA RACEWrite at 0x0000005b73c0 by goroutine 6:  main.incCounter()      /home/qmq/gopath/src/github.com/goinaction/code/test.go:49 +0x74Previous write at 0x0000005b73c0 by goroutine 7:  main.incCounter()      /home/qmq/gopath/src/github.com/goinaction/code/test.go:49 +0x74Goroutine 6 (running) created at:  main.main()      /home/qmq/gopath/src/github.com/goinaction/code/test.go:25 +0x68Goroutine 7 (running) created at:  main.main()      /home/qmq/gopath/src/github.com/goinaction/code/test.go:26 +0x89==================Final Counter: 2Found 1 data race(s)
==================WARNING: DATA RACEWrite at 0x0000005b73c0 by goroutine 7:  main.incCounter()      /home/qmq/gopath/src/github.com/goinaction/code/test.go:49 +0x74Previous write at 0x0000005b73c0 by goroutine 6:  main.incCounter()      /home/qmq/gopath/src/github.com/goinaction/code/test.go:49 +0x74Goroutine 7 (running) created at:  main.main()      /home/qmq/gopath/src/github.com/goinaction/code/test.go:26 +0x89Goroutine 6 (finished) created at:  main.main()      /home/qmq/gopath/src/github.com/goinaction/code/test.go:25 +0x68==================Final Counter: 3Found 1 data race(s)================

輸出小機率有3的情況,可能是goroutine沒有退出,所以發生了新goroutine中的值與上一次goroutine副本值相加的情況。對於這樣存在多個goroutine對一個共用資源進行操作的功能還是需要對其加鎖,或使用簡單的atomic,以及使用Go的特色通道 。

1.互斥鎖

package mainimport ("fmt""runtime""sync")var (counter intwg sync.WaitGroup        //互斥鎖    mutex sync.Mutex)func main() {wg.Add(2)go incCounter(1)go incCounter(2)wg.Wait()fmt.Printf("Final Counter: %d\n", counter)}func incCounter(id int) {defer wg.Done()for count := 0; count < 2; count++ {               //互斥鎖鎖定的臨界代碼塊,只允許同一時刻只有一個goroutine訪問mutex.Lock(){  //習慣地加上大括弧更清晰// Capture the value of counter.value := counter// Yield the thread and be placed back in queue.runtime.Gosched()// Increment our local value of counter.value++// Store the value back into counter.counter = value}mutex.Unlock()//解鎖}}

2.atomic包

package mainimport ("fmt""sync""sync/atomic""time")var (shutdown int64wg sync.WaitGroup)func main() {wg.Add(2)go doWork("A")go doWork("B")        //設定goroutine執行的時間time.Sleep(1 * time.Second)fmt.Println("Shutdown Now")        //安全標誌 判斷是否可以停止goroutine工作atomic.StoreInt64(&shutdown, 1)wg.Wait()}func doWork(name string) {defer wg.Done()for {fmt.Printf("Doing %s Work\n", name)time.Sleep(250 * time.Millisecond)if atomic.LoadInt64(&shutdown) == 1 {fmt.Printf("Shutting %s Down\n", name)break}}}

3.通道

package mainimport ("fmt""math/rand""sync""time")var wg sync.WaitGroupfunc init() {rand.Seed(time.Now().UnixNano())}func main() {court := make(chan int)wg.Add(2)go player("Ding", court)go player("Sha", court)court <- 1wg.Wait()}func player(name string, court chan int) {defer wg.Done()for {ball, ok := <-courtif !ok {fmt.Printf("Player %s Won\n", name)return}n := rand.Intn(100)if n%13 == 0 {fmt.Printf("Player %s Missed\n", name)close(court)return}fmt.Printf("Player %s Hit %d\n", name, ball)ball++court <- ball}}

  

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.