Golang脫坑指南: goroutine(不斷更新)

源代碼與測試代碼 https://github.com/YJZhangChina/GNP/tree/master/basic 下 goroutine_traps.go 與 goroutine_traps_test.gogit

1. 不安全的指針傳遞github

Goroutine的調度次序未知,若是執行屢次有指針傳遞的函數,且函數內存在寫操做,須要考慮髒讀和原子性問題。定義了Message結構體存儲當前值current,valueChange方法用於修改current爲當前步驟數step,並用Message指導後續操做。屢次運goroutine執行該方法,因爲指針傳遞,Message實例僅有一份,goroutine沒法保證函數流程的原子性,形成了寫無效和髒讀。適當增大循環次數size可更容易發現該問題。安全

Testing UnsafePointerPassing in GoroutineTraps // 模擬結果可能不一樣
After step 9 the value is 9.
After step 0 the value is 0.
After step 1 the value is 1.
After step 2 the value is 2.
After step 3 the value is 3.
After step 4 the value is 4.
After step 7 the value is 7.
After step 8 the value is 8.
After step 5 the value is 5.
After step 6 the value is 5. // Error

指針傳遞前對Message實例進行克隆,產生寫時複製的效果,修改後的結果不受影響。函數

Testing SafePointerPassing in GoroutineTraps // 模擬結果可能不一樣
After step 0 the value is 0.
After step 9 the value is 9.
After step 5 the value is 5.
After step 6 the value is 6.
After step 7 the value is 7.
After step 8 the value is 8.
After step 2 the value is 2.
After step 1 the value is 1.
After step 3 the value is 3.
After step 4 the value is 4.

goroutine_traps.go測試

package basic

import (
	"fmt"
	"sync"
)

type Message struct {
	current int
}

func valueChange(step int, message *Message, waiter *sync.WaitGroup) {
	message.current = step
	fmt.Printf("After step %d the value is %d.\n", step, message.current)
	waiter.Done()
}

goroutine_traps_test.gospa

package basic

import (
	"fmt"
	"sync"
	"testing"
)

func TestUnsafePointerPassing(t *testing.T) {
	fmt.Println("Testing UnsafePointerPassing in GoroutineTraps")
	size := 10
	var waiter sync.WaitGroup
	waiter.Add(size)
	message := &Message{current: 1}
	for i := 0; i < size; i++ {
		go valueChange(i+1, message, &waiter)
	}
	waiter.Wait()
}

func TestSafePointerPassing(t *testing.T) {
	fmt.Println("Testing SafePointerPassing in GoroutineTraps")
	size := 10
	var waiter sync.WaitGroup
	waiter.Add(size)
	message := &Message{current: 1}
	for i := 0; i < 10; i++ {
		var clone = new(Message)
		*clone = *message
		go valueChange(i+1, clone, &waiter)
	}
	waiter.Wait()
}
相關文章
相關標籤/搜索