乐闻世界logo
搜索文章和话题

How do you handle concurrent access to shared resources in Go?

1个答案

1

In Go, handling concurrent access to shared resources primarily involves two mechanisms: using Mutex and using Channel. Below, I'll explain both methods in detail, along with specific usage examples.

1. Using Mutex

Mutex is a synchronization primitive that ensures only one goroutine can access a shared resource at a time. The Go standard library's sync package provides the Mutex type for implementing mutexes.

Example:

Assume an Account struct where we want to safely update the balance across multiple goroutines.

go
package main import ( "fmt" "sync" "time" ) // Account represents a bank account // type Account struct { // balance int // mutex sync.Mutex // } // Deposit deposits money func (a *Account) Deposit(amount int) { a.mutex.Lock() // Acquire the lock a.balance += amount a.mutex.Unlock() // Release the lock } // Balance queries the balance func (a *Account) Balance() int { a.mutex.Lock() // Acquire the lock balance := a.balance a.mutex.Unlock() // Release the lock return balance } func main() { var wg sync.WaitGroup account := &Account{} // Concurrently execute multiple deposit operations for i := 1; i <= 5; i++ { wg.Add(1) go func(amount int) { defer wg.Done() account.Deposit(amount) }(100 * i) } wg.Wait() fmt.Printf("Account balance: %d\n", account.Balance()) }

In this example, Deposit and Balance methods use mutex.Lock() and mutex.Unlock() to ensure that only one goroutine accesses the balance at a time during modification or reading.

2. Using Channels

Channels are used in Go to pass messages between goroutines and can also synchronize access to shared resources. By ensuring all operations on shared resources are performed through channels, synchronization can be achieved.

Example:

Assume multiple goroutines need to write data to the same log file. We can create a dedicated goroutine to manage access to the file, while other goroutines send write requests via channels.

go
package main import ( "fmt" "sync" ) // Log request // type logRequest struct { // data string // response chan bool // } func logger(requests chan logRequest) { for req := range requests { fmt.Println("Log:", req.data) req.response <- true } } func main() { logChannel := make(chan logRequest) defer close(logChannel) var wg sync.WaitGroup // Start the log processing goroutine go logger(logChannel) // Send log requests for i := 0; i < 5; i++ { wg.Add(1) go func(id int) { defer wg.Done() response := make(chan bool) logChannel <- logRequest{data: fmt.Sprintf("This is log entry %d", id), response: response} <-response // Wait for log processing to complete }(i) } wg.Wait() }

In this example, all log-writing requests are sent via logChannel to the logger goroutine. The logger goroutine processes these requests serially, preventing concurrent writes. After each write operation, a response channel notifies the requester.

Summary

Depending on the application scenario, choose between using Mutex or Channels for handling concurrent access to shared resources. Mutex is suitable for simple protection of shared resources, while Channels are better for scenarios requiring goroutine communication or complex synchronization. Both methods have pros and cons; selecting the appropriate method can effectively enhance program safety and efficiency.

2024年8月7日 18:22 回复

你的答案