goroutines 就是一系列的 Thread 操作,意思即一支程式同時進行好幾個小程式。使用go的時候程式會將go所要執行的項目放到背景執行,繼續進行主程式的程式碼,用下面的程式碼來舉例
func main() {
var a [10]int
for i := 0; i < 10; i++ {
go func(i int) {
for {
a[i]++ // 寫入 a
runtime.Gosched() // 交出控制權,否則程式會不斷的在這 for 迴圈之中
}
}(i)
}
time.Sleep(time.Millisecond) // 加入這行主要是因為避免程式結束太快,導致後面來不及執行
fmt.Println(a) // 讀取 a
}
輸出結果如下 (但每次結果不盡相同,因為每次開的 Thread 的切入時間點可能都不太一樣,因此造成這個情況,這先不用糾結):
// 第一次執行
[425 515 600 353 411 467 444 452 515 511]
// 第二次執行
[775 669 667 668 478 402 467 817 819 530]
goroutine 可能的切換點有以下幾種情況
ps. 上面有些沒看過的會在後面介紹
在執行過程中,可以在終端機中透過以下指令來檢測數據訪問衝突
go run -race <file_name>
以我的例子而言是輸入
go run -race day12.go
得到的結果為
==================
WARNING: DATA RACE
Read at 0x00c00013e000 by main goroutine:
main.main()
/Users/luckyyuho/Documents/Golang/ithome/2022/day12/day12.go:20 +0x158
Previous write at 0x00c00013e000 by goroutine 7:
main.main.func1()
/Users/luckyyuho/Documents/Golang/ithome/2022/day12/day12.go:14 +0x58
main.main.func2()
/Users/luckyyuho/Documents/Golang/ithome/2022/day12/day12.go:17 +0x44
Goroutine 7 (running) created at:
main.main()
/Users/luckyyuho/Documents/Golang/ithome/2022/day12/day12.go:12 +0x6c
==================
可以看到有警告提示,那主要是因為這程式中有兩行會互相衝突,分別為寫入的 a[i]++ 與讀取的 fmt.Println(a) 因為有可能在讀取的瞬間,另一個 Thread 剛好正在寫入,因此產生這個警告,看似一個小問題,但是有時候會很嚴重,打個比方,套用參考來源1的範例,如果今天同一個銀行的網路銀行有提款功能,而有個人的帳戶有1500元,但同時在兩台電腦都登入了要提款,兩台電腦都送出了提領1000的請求會怎樣呢?會不會發現1500分別各提領1000還剩500?這樣一來就會造成資料庫的衝突,那麼我們要怎麼避免這個問題呢?讓我們繼續看下去:)
https://github.com/luckyuho/ithome30-golang