Go sync
The sync package in Go is used to control concurrent read and write access to shared resources. However, its control is limited to the current process within the same machine, and it cannot span across multiple machines or processes.
sync.WaitGroup
In Go, sync.WaitGroup can be utilized to synchronize concurrent tasks. It internally maintains a counter:
- When N concurrent tasks are launched, the counter is incremented by N
- As each task completes, it calls the Done() method to decrement the counter by 1
- The Wait() method is used to block until all concurrent tasks have completed, which occurs when the counter reaches 0
var wg sync.WaitGroup
func worker(id int) {
defer wg.Done() //It's typically called at the end of a goroutine to signal completion
//Execute subsequent tasks...
}
func main() {
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(i)
}
wg.Wait() //Wait for all goroutines to finish
}
sync.Mutex
sync.Mutex (Mutex stands for Mutual Exclusion) is used to ensure that only one goroutine can read or write to a shared resource at a time, while others must wait until the mutex is released.
var mu sync.Mutex
func OperateResource() {
mu.Lock()
defer mu.Unlock()
//Accessing shared resources
}
sync.RWMutex
sync.RWMutex (Read-Write Mutex) is more suitable than sync.Mutex in scenarios where reads are frequent and writes are rare. It provides:
- Shared read locks: When a goroutine acquires a shared read lock, other goroutines can also acquire shared read locks, but those seeking a write lock must wait.
- Exclusive write locks: When a goroutine acquires an exclusive write lock, all other goroutines must wait, similar to sync.Mutex.
var rwmu sync.RWMutex
func readResource() {
//Any goroutine can acquire a shared read lock as long as the resource is not currently locked by an exclusive write lock.
//However, an exclusive write lock must wait if the resource is locked by any shared read lock or another exclusive write lock.
rwmu.RLock()
defer rwmu.RUnlock()
//Reading shared resources
}
func writeResource() {
//Requires the resource to be unlocked by any previous exclusive write lock or shared read lock
rwmu.Lock()
defer rwmu.Unlock()
//Writing to shared resources
}
sync.Once
sync.Once is used to ensure that certain operations are executed only once in highly concurrent scenarios, such as initializing resources, loading configuration files only once, or closing a channel only once. Due to its simple and efficient concurrency control mechanism, sync.Once is very useful in concurrent programming.
var (
wg sync.WaitGroup
once sync.Once
times int
)
func main() {
for i := 0; i < 5; i++ {
wg.Add(1)
go initResourceWrapper()
}
wg.Wait()
}
//When you want to perform an initialization operation only once
func initResource() {
times++
fmt.Println("Resource initialized times:", times)
}
func initResourceWrapper() {
defer wg.Done()
once.Do(initResource)
}
Take a break
πππ γBTTH Year EP104γXiao Yan vs Feng Qing'er on the Four Pavilions Grand Meeting