已經把《Go 語言并發之道》通讀了一遍,非常不錯的一本書,對于理解掌握Go語言的并發知識有很大的幫助,接下來我會把書中有用的知識通過代碼示例出來,把一些比較好的知識點記錄下來,
首先我們來看一段代碼
var data int
go func() { data++ }()
if data =https://www.cnblogs.com/dk168/archive/2022/11/11/= 0 {
fmt.Println(" the value is 0.")
} else {
fmt.Printf(" the value is %v.\n", data)
}
這段代碼我們想把data + 1 后列印出來,但是結果列印出來的效果是 “the value is 0.”, 沒有達到我們的預期,主要是因為呼叫 data++ 的這個goroutine沒有先執行, 并發的難點就是控制程式執行的先后順序, 那么我們能不能這樣改進一下呢? 加一個sleep讓主goroutine等待一下,
var data int
go func() { data++ }()
time.Sleep(1 * time.Second)
if data =https://www.cnblogs.com/dk168/archive/2022/11/11/= 0 {
fmt.Println(" the value is 0.")
} else {
fmt.Printf(" the value is %v.\n", data)
}
列印出來的結果是 “the value is 1.”, 似乎達到了我們的預期, 但是實際是是不行的,也許data++方法里面還有耗時的操作,那程式運行的結果又有不確定性了,
這個程式還有個很大的問題, 兩個goroutine共享了記憶體data, 如果這個data是只讀的那還好,不會有什么影響,但是如果它是需要改變的,那么兩個goroutine拿到的資料會存在不確定性,那么是否能夠通過加鎖來解決這個問題呢? 如下示例代碼
var memoryAccess sync.Mutex
var data int
go func() {
memoryAccess.Lock()
data++
memoryAccess.Unlock()
}()
memoryAccess.Lock()
if data =https://www.cnblogs.com/dk168/archive/2022/11/11/= 0 {
fmt.Println(" the value is 0.")
} else {
fmt.Printf(" the value is %v.\n", data)
}
memoryAccess.Unlock()
通過加鎖我們能保證訪問data的時候是獨占的,但是它依然解決不了代碼執行先后問題,而且看上去很不優雅, 既優雅又能解決問題的方法是下面的代碼
c := make(chan int)
var data int
go func() {
data++
c <- data
}()
data = <-c
if data =https://www.cnblogs.com/dk168/archive/2022/11/11/= 0 {
fmt.Println(" the value is 0.")
} else {
fmt.Printf(" the value is %v.\n", data)
}
輸出結果“the value is 1.”
上面的代碼定義了一個channel, 通過channel來傳遞value, 主goroutine遇到讀取channel( <-c)的地方會等待,等待副goroutine把值填進去(c <- data), 其它部分的代碼并發執行,
這里貼出書上Go語言并發性哲學總結: 追求簡潔, 盡量使用channel, 并且認為goroutine的使用是沒有成本的,
Go語言的座右銘: 使用通信來共享記憶體,而不是通過共享記憶體來通信
總結
這個例子雖然很簡單,但是它能夠引導我們進入Go語言并發的世界,讓我們明白如何通過goroutine和channel來優雅的寫出并發代碼, 后續我們將列舉出更多的示例,通過示例來說明一下知識,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/531808.html
標籤:其他
上一篇:支持JDK19虛擬執行緒的web框架之四:看原始碼,了解quarkus如何支持虛擬執行緒
下一篇:05python字串
