Golang recommended communication and synchronization through the channel, but in the actual development of the sync pack is also very much, in the Ethereum source code also has a lot of this kind of application embodiment.
The Go Sync Pack offers: Sync. Mutex,sync. Rmutex,sync. Once,sync. Cond,sync. Waitgroup,sync.atomic, and so on, the text mainly on the use of Sync.mutex,sync.rmutex and Sync.waitgroup described, follow-up will introduce other methods of the use of instructions.
Sync contains a Locker interface:
type Locker interface { Lock() Unlock()}
The interface has only two methods, Lock () and Unlock (). The entire sync package is implemented around this interface.
Mutex Mutex
Mutex mutex is a concrete implementation of locker, there are two methods:
func (m *Mutex) Lock()func (m *Mutex) Unlock()
A mutex can only be locked by one goroutine at a time, and the other goroutine will block until the mutex is unlocked and then re-compete for the lock on the mutex.
Unlocking an unlocked mutex will result in a run-time error.
package mainimport ( "fmt" "sync" "time")func main() { ch := make(chan struct{}, 2) var l sync.Mutex go func() { l.Lock() defer l.Unlock() fmt.Println("goroutine1: 锁定大概 2s") time.Sleep(time.Second * 2) fmt.Println("goroutine1: 解锁了,可以开抢了!") ch <- struct{}{} }() go func() { fmt.Println("groutine2: 等待解锁") l.Lock() defer l.Unlock() fmt.Println("goroutine2: 我锁定了") ch <- struct{}{} }() // 等待 goroutine 执行结束 for i := 0; i < 2; i++ { <-ch }}
Read/write Lock Rwmutex
Read-write lock is for the read and write operation of the mutex, read-write and mutual exclusion lock the biggest difference is that read, write can be locked separately. Generally used in a large number of read operations, a small number of write operations:
func (rw *RWMutex) Lock()func (rw *RWMutex) Unlock()func (rw *RWMutex) RLock()func (rw *RWMutex) RUnlock()
Since there is a need to differentiate between read and write locks, the read-write lock defines:
Read lock (Rlock) to lock the read operation
Read Unlock (runlock), unlock read lock
Write lock (lock), which locks the write operation
Write Unlock (Unlock) to unlock the write lock
Do not mix locking and unlocking, such as: Lock and Runlock, Rlock, and Unlock. A run-time error is caused by a read or write lock on an unread lock, or a written lock on a read-write lock that is not written.
How do you understand read-write locks?
Only one goroutine can get a write lock at the same time.
You can also have any number of Gorouinte to obtain a read lock.
Only write locks or read locks (read and write mutexes) can exist at the same time.
That is, when a goroutine gets a write lock, the rest of the read lock or write lock will block until the write is unlocked, and when one of the goroutine gets a read lock, the other read locks can still continue; when there is one or any number of read locks, The write lock waits for all read locks to be unlocked before a write lock can be made. So the read lock (rlock) purpose here is actually to tell the write lock: There are a lot of people reading the data, you need to wait until they read (read unlock) and then write (write lock).
package mainimport ( "fmt" "math/rand" "sync")var count intvar rw sync.RWMutexfunc main() { ch := make(chan struct{}, 10) for i := 0; i < 5; i++ { go read(i, ch) } for i := 0; i < 5; i++ { go write(i, ch) } for i := 0; i < 10; i++ { <-ch }}func read(n int, ch chan struct{}) { rw.RLock() fmt.Printf("goroutine %d 进入读操作...\n", n) v := count fmt.Printf("goroutine %d 读取结束,值为:%d\n", n, v) rw.RUnlock() ch <- struct{}{}}func write(n int, ch chan struct{}) { rw.Lock() fmt.Printf("goroutine %d 进入写操作...\n", n) v := rand.Intn(1000) count = v fmt.Printf("goroutine %d 写入结束,新值为:%d\n", n, v) rw.Unlock() ch <- struct{}{}}
Waitgroup
Waitgroup is used to wait for a set of goroutine to end and usage is relatively straightforward. It has three methods:
func (wg *WaitGroup) Add(delta int)func (wg *WaitGroup) Done()func (wg *WaitGroup) Wait()
Add the number of Goroutine to be added. Done executes a quantity minus 1. Wait waits for the end:
package mainimport ( "fmt" "sync")func main() { var wg sync.WaitGroup for i, s := range seconds { // 计数加 1 wg.Add(1) go func(i, s int) { // 计数减 1 defer wg.Done() fmt.Printf("goroutine%d 结束\n", i) }(i, s) } // 等待执行结束 wg.Wait() fmt.Println("所有 goroutine 执行结束")}
ATTENTION, WG. The ADD () method must be executed before Goroutine starts.