在 Golang 中处理对共享资源的并发访问主要有几种方法,其中最常用的是使用互斥锁(Mutex)和信道(Channel)。接下来我会详细介绍这两种方法,并给出相应的代码示例。
1. 使用互斥锁(Mutex)
互斥锁是一种同步原语,用于确保多个 goroutine 在访问共享资源时不会发生冲突。使用 sync.Mutex 来保护共享资源,确保一次只有一个 goroutine 可以访问该资源。
示例:
gopackage main import ( "fmt" "sync" ) var ( counter int lock sync.Mutex ) func increment() { lock.Lock() // 在访问共享资源之前加锁 defer lock.Unlock() // 使用 defer 确保锁一定会被释放 counter++ // 安全地修改共享资源 } func main() { var wg sync.WaitGroup // 创建多个 goroutine 来模拟并发访问 for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() increment() }() } wg.Wait() // 等待所有 goroutine 完成 fmt.Println("Counter:", counter) }
在这个例子中,我们使用互斥锁确保对 counter 的访问是线程安全的。无论启动多少个 goroutine,最终的输出都会是 100。
2. 使用信道(Channel)
信道是 Go 语言中一个非常重要的特性,可以用于在不同的 goroutine 之间安全地传递数据。通过信道可以控制数据的流动,因此也可以用来同步对共享资源的访问。
示例:
gopackage main import ( "fmt" "sync" ) func worker(jobs <-chan int, results chan<- int) { for job := range jobs { results <- job * 2 // 处理工作并将结果发送到结果信道 } } func main() { jobs := make(chan int, 100) results := make(chan int, 100) var wg sync.WaitGroup // 启动工作者处理任务 for w := 0; w < 3; w++ { wg.Add(1) go func() { defer wg.Done() worker(jobs, results) }() } // 发送任务到工作信道 for j := 1; j <= 5; j++ { jobs <- j } close(jobs) wg.Wait() // 等待所有工作者完成 close(results) // 关闭结果信道 // 收集所有结果 for result := range results { fmt.Println(result) } }
在这个例子中,我们创建了一个工作信道和一个结果信道。不同的工作者 goroutine 从 jobs 信道接收任务,并将处理后的结果发送到 results 信道,从而实现了对共享资源的安全访问和数据同步。
总结
在 Go 中,处理并发对共享资源的访问通常依赖互斥锁和信道两种机制。选择使用哪种机制取决于具体的应用场景。互斥锁适合保护简单的共享数据,而信道则更适合在不同 goroutine 之间进行数据的通信和同步。
2024年10月26日 16:52 回复