解决策略和方法
- 互斥锁(Mutex):
- 原理:互斥锁用于保护共享资源,同一时间只有一个协程可以获取锁并访问共享资源,其他协程需要等待锁被释放。
- 应用场景:适用于对共享资源读写操作都可能发生资源竞争的情况。
- 读写锁(RWMutex):
- 原理:读写锁区分了读操作和写操作。多个协程可以同时进行读操作,但写操作时需要独占锁,以防止读 - 写、写 - 写冲突。
- 应用场景:适用于读操作远多于写操作的场景,这样可以提高并发读的效率。
- 通道(Channel):
- 原理:通道用于在协程之间传递数据,它本身是线程安全的。通过通道传递数据可以避免共享资源的竞争。
- 应用场景:适用于将数据生成和数据消费分离,通过通道来传递数据。
- 原子操作(Atomic Operations):
- 原理:原子操作是不可分割的操作,在执行过程中不会被其他操作打断,Go标准库提供了原子操作的支持。
- 应用场景:适用于对简单数据类型(如整数)的操作,避免使用锁带来的开销。
同步原语使用示例
- 互斥锁示例:
package main
import (
"fmt"
"sync"
)
var (
mu sync.Mutex
count int
)
func generator(wg *sync.WaitGroup) {
defer wg.Done()
mu.Lock()
count++
fmt.Printf("Generator incremented count to %d\n", count)
mu.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go generator(&wg)
}
wg.Wait()
}
- 读写锁示例:
package main
import (
"fmt"
"sync"
)
var (
rwmu sync.RWMutex
value int
)
func reader(wg *sync.WaitGroup) {
defer wg.Done()
rwmu.RLock()
fmt.Printf("Reader read value: %d\n", value)
rwmu.RUnlock()
}
func writer(wg *sync.WaitGroup) {
defer wg.Done()
rwmu.Lock()
value++
fmt.Printf("Writer incremented value to %d\n", value)
rwmu.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go reader(&wg)
}
for i := 0; i < 2; i++ {
wg.Add(1)
go writer(&wg)
}
wg.Wait()
}
- 通道示例:
package main
import (
"fmt"
"sync"
)
func dataGenerator(ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func dataConsumer(ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
for num := range ch {
fmt.Printf("Consumer received: %d\n", num)
}
}
func main() {
var wg sync.WaitGroup
ch := make(chan int)
wg.Add(1)
go dataGenerator(ch, &wg)
for i := 0; i < 3; i++ {
wg.Add(1)
go dataConsumer(ch, &wg)
}
wg.Wait()
}
- 原子操作示例:
package main
import (
"fmt"
"sync"
"sync/atomic"
)
var count int64
func increment(wg *sync.WaitGroup) {
defer wg.Done()
atomic.AddInt64(&count, 1)
fmt.Printf("Incremented count to %d\n", atomic.LoadInt64(&count))
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go increment(&wg)
}
wg.Wait()
}