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:

  1. When N concurrent tasks are launched, the counter is incremented by N
  2. As each task completes, it calls the Done() method to decrement the counter by 1
  3. 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:

  1. 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.
  2. 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