golang并发锁如何使用
更新时间:2023-11-10Go语言中的并发锁
并发锁是Go语言中实现并发安全的一种机制,可以保证不同协程之间的临界区代码不被同时执行。Go语言中提供了多种锁机制,比如:互斥锁、读写锁、条件变量。
互斥锁 Mutex
互斥锁Mutex是Go语言中最基础的并发锁机制,可以在代码块前后使用Mutex的Lock()和Unlock()方法实现锁的获取和释放。
package main import ( "fmt" "sync" "time" ) type Counter struct { sum int mux sync.Mutex } func (c *Counter) Add(i int) { c.mux.Lock() defer c.mux.Unlock() time.Sleep(100 * time.Millisecond) c.sum += i } func (c *Counter) Value() int { c.mux.Lock() defer c.mux.Unlock() return c.sum } func main() { var wg sync.WaitGroup var counter Counter for i := 0; i < 1000; i++ { wg.Add(1) go func() { counter.Add(1) wg.Done() }() } wg.Wait() fmt.Println(counter.Value()) }
在上面的代码中,我们定义了一个Counter类型,它有一个内部字段sum,以及一个互斥锁mux。Add方法和Value方法都使用了锁,以保证它们对于字段sum的访问是安全的。
读写锁 RWMutex
读写锁是一种比互斥锁更高效的锁机制,它允许多个协程同时读取某一个共享资源,但是在写的时候必须互斥访问,保证写的安全性。
package main import ( "fmt" "sync" "time" ) type Counter struct { sum int mux sync.RWMutex } func (c *Counter) Add(i int) { c.mux.Lock() defer c.mux.Unlock() time.Sleep(100 * time.Millisecond) c.sum += i } func (c *Counter) Value() int { c.mux.RLock() defer c.mux.RUnlock() return c.sum } func main() { var wg sync.WaitGroup var counter Counter for i := 0; i < 1000; i++ { wg.Add(1) go func() { counter.Add(1) wg.Done() }() } wg.Wait() fmt.Println(counter.Value()) }
在上面的代码中,我们将Mutex替换成了RWMutex,Add方法仍然使用互斥锁来保证写的安全性,而Value方法则使用读锁来允许多协程之间的并发读取。
条件变量 Cond
条件变量是一种在协程之间等待和通知的机制,它可以让协程在满足特定条件之前等待,或者在满足特定条件时通知其他协程。
package main import ( "fmt" "sync" "time" ) type Counter struct { sum int mux sync.Mutex cond *sync.Cond } func NewCounter() *Counter { c := &Counter{} c.cond = sync.NewCond(&c.mux) return c } func (c *Counter) Add(i int) { c.mux.Lock() defer c.mux.Unlock() time.Sleep(100 * time.Millisecond) c.sum += i c.cond.Broadcast() } func (c *Counter) Wait(n int) { c.mux.Lock() defer c.mux.Unlock() for c.sum < n { c.cond.Wait() } } func main() { var wg sync.WaitGroup var counter = NewCounter() for i := 0; i < 1000; i++ { wg.Add(1) go func() { counter.Add(1) wg.Done() }() } wg.Wait() counter.Wait(1000) fmt.Println(counter.Value()) }
在上面的代码中,我们使用了一个条件变量来实现等待某一个特定条件。Wait方法会在条件变量发生变化时被唤醒,并返回。
总结
在Go语言中,我们可以通过互斥锁、读写锁和条件变量等不同的锁机制来实现并发安全。我们应该根据具体的场景来选择适合的锁机制。
互斥锁是Go语言中最基础的锁机制,其安全性和性能表现都比较稳定。但是当场景中存在大量的读操作时,互斥锁对性能的影响将会相对较大,而读写锁则可以在不降低写性能的前提下提高并发度。
条件变量则是一种轻量级的等待和通知机制,它可以让协程更高效地等待某些必要条件的发生,并通知其他协程执行特定的操作。
总之,在选择锁机制时应该根据具体的场景来选择合适的锁,以保证代码的性能、安全和可维护性。