------------------------------------------------------------ 臨時對象池 Pool 用於存儲臨時對象,它將使用完畢的對象存入對象池中,在須要的時候取出來重複使用,目的是爲了不重複建立相同的對象形成 GC 負擔太重。其中存放的臨時對象隨時可能被 GC 回收掉(若是該對象再也不被其它變量引用)。 從 Pool 中取出對象時,若是 Pool 中沒有對象,將返回 nil,可是若是給 Pool.New 字段指定了一個函數的話,Pool 將使用該函數建立一個新對象返回。 Pool 能夠安全的在多個例程中並行使用,但 Pool 並不適用於全部空閒對象,Pool 應該用來管理併發的例程共享的臨時對象,而不該該管理短壽命對象中的臨時對象,由於這種狀況下內存不能很好的分配,這些短壽命對象應該本身實現空閒列表。 Pool 在開始使用以後,不能再被複制。 ------------------------------ type Pool struct { // 建立臨時對象的函數 New func() interface{} } // 向臨時對象池中存入對象 func (p *Pool) Put(x interface{}) // 從臨時對象池中取出對象 func (p *Pool) Get() interface{} ------------------------------------------------------------ 單次執行 Once 的做用是屢次調用但只執行一次,Once 只有一個方法,Once.Do(),向 Do 傳入一個函數,這個函數在第一次執行 Once.Do() 的時候會被調用,之後再執行 Once.Do() 將沒有任何動做,即便傳入了其它的函數,也不會被執行,若是要執行其它函數,須要從新建立一個 Once 對象。 Once 能夠安全的在多個例程中並行使用。 ------------------------------ // 屢次調用僅執行一次指定的函數 f func (o *Once) Do(f func()) ------------------------------ // 示例:Once func main() { var once sync.Once onceBody := func() { fmt.Println("Only once") } done := make(chan bool) for i := 0; i < 10; i++ { go func() { once.Do(onceBody) // 屢次調用只執行一次 done <- true }() } for i := 0; i < 10; i++ { <-done } } // 輸出結果: // Only once ------------------------------------------------------------ 互斥鎖 互斥鎖用來保證在任一時刻,只能有一個例程訪問某對象。Mutex 的初始值爲解鎖狀態。Mutex 一般做爲其它結構體的匿名字段使用,使該結構體具備 Lock 和 Unlock 方法。 Mutex 能夠安全的在多個例程中並行使用。 ------------------------------ // Locker 接口包裝了基本的 Lock 和 UnLock 方法,用於加鎖和解鎖。 type Locker interface { Lock() Unlock() } // Lock 用於鎖住 m,若是 m 已經被加鎖,則 Lock 將被阻塞,直到 m 被解鎖。 func (m *Mutex) Lock() // Unlock 用於解鎖 m,若是 m 未加鎖,則該操做會引起 panic。 func (m *Mutex) Unlock() ------------------------------ // 示例:互斥鎖 type SafeInt struct { sync.Mutex Num int } func main() { count := SafeInt{} done := make(chan bool) for i := 0; i < 10; i++ { go func(i int) { count.Lock() // 加鎖,防止其它例程修改 count count.Num += i fmt.Print(count.Num, " ") count.Unlock() // 修改完畢,解鎖 done <- true }(i) } for i := 0; i < 10; i++ { <-done } } // 輸出結果(不固定): // 2 11 14 18 23 29 36 44 45 45 ------------------------------------------------------------ 讀寫互斥鎖 RWMutex 比 Mutex 多了一個「讀鎖定」和「讀解鎖」,可讓多個例程同時讀取某對象。RWMutex 的初始值爲解鎖狀態。RWMutex 一般做爲其它結構體的匿名字段使用。 Mutex 能夠安全的在多個例程中並行使用。 ------------------------------ // Lock 將 rw 設置爲寫鎖定狀態,禁止其餘例程讀取或寫入。 func (rw *RWMutex) Lock() // Unlock 解除 rw 的寫鎖定狀態,若是 rw 未被寫鎖定,則該操做會引起 panic。 func (rw *RWMutex) Unlock() // RLock 將 rw 設置爲讀鎖定狀態,禁止其餘例程寫入,但能夠讀取。 func (rw *RWMutex) RLock() // Runlock 解除 rw 的讀鎖定狀態,若是 rw 未被讀鎖頂,則該操做會引起 panic。 func (rw *RWMutex) RUnlock() // RLocker 返回一個互斥鎖,將 rw.RLock 和 rw.RUnlock 封裝成了一個 Locker 接口。 func (rw *RWMutex) RLocker() Locker ------------------------------------------------------------ 組等待 WaitGroup 用於等待一組例程的結束。主例程在建立每一個子例程的時候先調用 Add 增長等待計數,每一個子例程在結束時調用 Done 減小例程計數。以後,主例程經過 Wait 方法開始等待,直到計數器歸零才繼續執行。 ------------------------------ // 計數器增長 delta,delta 能夠是負數。 func (wg *WaitGroup) Add(delta int) // 計數器減小 1 func (wg *WaitGroup) Done() // 等待直到計數器歸零。若是計數器小於 0,則該操做會引起 panic。 func (wg *WaitGroup) Wait() ------------------------------ // 示例:組等待 func main() { wg := sync.WaitGroup{} wg.Add(10) for i := 0; i < 10; i++ { go func(i int) { defer wg.Done() fmt.Print(i, " ") }(i) } wg.Wait() } // 輸出結果(不固定): // 9 3 4 5 6 7 8 0 1 2 ------------------------------------------------------------ 條件等待 條件等待經過 Wait 讓例程等待,經過 Signal 讓一個等待的例程繼續,經過 Broadcast 讓全部等待的例程繼續。 在 Wait 以前應當手動爲 c.L 上鎖,Wait 結束後手動解鎖。爲避免虛假喚醒,須要將 Wait 放到一個條件判斷循環中。官方要求的寫法以下: c.L.Lock() for !condition() { c.Wait() } // 執行條件知足以後的動做... c.L.Unlock() Cond 在開始使用以後,不能再被複制。 ------------------------------ type Cond struct { L Locker // 在「檢查條件」或「更改條件」時 L 應該鎖定。 } // 建立一個條件等待 func NewCond(l Locker) *Cond // Broadcast 喚醒全部等待的 Wait,建議在「更改條件」時鎖定 c.L,更改完畢再解鎖。 func (c *Cond) Broadcast() // Signal 喚醒一個等待的 Wait,建議在「更改條件」時鎖定 c.L,更改完畢再解鎖。 func (c *Cond) Signal() // Wait 會解鎖 c.L 並進入等待狀態,在被喚醒時,會從新鎖定 c.L func (c *Cond) Wait() ------------------------------ // 示例:條件等待 func main() { condition := false // 條件不知足 var mu sync.Mutex cond := sync.NewCond(&mu) // 讓例程去創造條件 go func() { mu.Lock() condition = true // 更改條件 cond.Signal() // 發送通知:條件已經知足 mu.Unlock() }() mu.Lock() // 檢查條件是否知足,避免虛假通知,同時避免 Signal 提早於 Wait 執行。 for !condition { // 等待條件知足的通知,若是收到虛假通知,則循環繼續等待。 cond.Wait() // 等待時 mu 處於解鎖狀態,喚醒時從新鎖定。 } fmt.Println("條件知足,開始後續動做...") mu.Unlock() } // 輸出結果: // 條件知足,開始後續動做... ------------------------------------------------------------