包 (package)
- Golang目前約有150個標準包
- 官網有所有package的文檔 https://golang.org/pkg/
- 第三方package的資源多位於github
安裝第三方包
再命令行輸入1
go get github網址
會安裝第三方包,默認會安裝到%GOPATH%/src/ 中
線程同步 (sync) 與鎖 (lock)
- 多個線程之間可能同時使用同一個資源
- 資源在線程之間共享,加鎖可以使資源更安全的被取用或是寫入
- 但在進行只有讀取操作時,不加鎖可讓執行效率更高
情況一: 資源共享讀取寫入 — 不加鎖
在不加鎖的情況下,開啟多個線程同時去對map操作
example
1 | package main |
result 1
1 | map[1:444] |
result 2
1 | map[1:555] |
result 3
1 | map[1:222] |
conclusion
我們可以看到每次的結果都不一樣,證明了線程之間存在競爭關係
- 哪個線程得到最後修改的權限,值就會是該線程修改的結果
這不是理想執行的情況,會造成資源取用不安全
在編譯時可透過-race
參數來檢查是否存在線程競爭,如果存在,編譯完成後,執行時會發出警告1
go build -race go_dev/day12/example/example_sync
情況二: 資源共享讀取寫入 — 互斥鎖
- 互斥鎖:不管讀的線程 或是 寫的線程 每次都只能有一個線程進入到加鎖的代碼中去執行代碼
- 線程鎖相關的package於”sync”包中
var 變量 sync.Mutex
: 定義一個”互斥鎖”類型變量.Lock()
:加鎖變量.Unlock()
:釋放鎖
1 | package main |
[1] 定義一個變量lock
為互斥鎖類型(sync.Mutex
)
[2] 不要讓主線程直接結束,故sleep一段時間之後等待子線程都執行完畢再結束
result
1 | map[1:59] |
情況三: 資源共享讀取寫入 — 讀寫鎖
讀寫鎖:一種特殊鎖,對共享資源訪問者劃分讀者和寫者,讀操作可並發重入,寫操作是互斥的。
讀線程進到讀寫鎖中,其他 讀線程 仍能進入,但 寫線程 不能進入
寫線程進到讀寫鎖中,其他 讀線程 不能進入,且 寫線程 亦不能進入讀多寫少的情況下,讀寫鎖性能最高
var 變量 sync.RWMutex
: 定義一個”讀寫鎖”類型
讀者鎖:
變量.RLock()
:只有讀線程可以進入RLock鎖,且讀線程在執行時其他讀線程仍能進入鎖中,與RUnlock之間通常為讀取相關的操作變量.RUnlock()
: 釋放鎖
互斥鎖:
變量.Lock()
:只有寫線程可以進入Lock鎖,且寫線程在執行時其他不管是讀或是寫線程皆無法進入鎖中,與Unlock之間通常為寫入相關的操作變量.Unlock()
: 釋放鎖
1 | package main |
result
1 | map[1:81 2:2 3:3 4:4] |
atomic package
位於sync/atomic
包中
*atomic.AddInt
相關函數,可讓整數同一時間只會有一個線程能修改此數,絕對不存在兩個或多個線程同時操作atomic.AddInt
中的整數
- 使用
atomic.AddInt
可對同一時間併發多少線程記數
- 但是記數完時需要打印該值,仍會牽扯到線程互相競爭打印該值的問題
- 透過
atomic.LoadInt
相關函數,可直接讀取該值
用法
拿int32
類型作為示範1
2
3atomic.Addint32(int32類型整數的指針,每次增加的差值)
atomic.LoadInt32(int32類型整數的指針)
- 其他方法可參考官方文檔
範例
1 | package main |
result
1 | map[1:81 2:2 3:3 4:4] |