高并发下的秘宝:Go语言sync包并发同步原语探秘(2)
2023-12-14 11:59:18
Go并发下的秘宝:sync包并发同步原语探秘(2)
开篇点题
在上篇文章中,我们为大家介绍了Go语言中sync包的基本同步原语sync.Map、sync.Pool和sync.Once的概念和简单应用,还对sync.Map和map进行了比较。那么,今天我们就继续来深入探讨一下sync包中其他的并发同步原语,包括互斥锁、死锁和goroutine等,并提供一些实用代码示例,帮助您更好地理解这些同步原语的用法和优势。
sync.Mutex:互斥锁的利器
sync.Mutex是一个非常重要的并发同步原语,它允许您控制对共享资源的访问,防止出现数据竞争问题。sync.Mutex本质上是一个互斥锁,一次只能有一个goroutine持有它。当一个goroutine获取互斥锁时,其他goroutine必须等待,直到该goroutine释放互斥锁。
以下是一个使用sync.Mutex的简单示例:
package main
import (
"fmt"
"sync"
)
var count int
var mutex sync.Mutex
func main() {
for i := 0; i < 100; i++ {
go increment()
}
fmt.Println("Final value of count:", count)
}
func increment() {
mutex.Lock()
defer mutex.Unlock()
count++
}
在这个示例中,我们使用sync.Mutex来保护对count变量的访问。这样,即使有多个goroutine同时尝试修改count,也不会出现数据竞争问题。
sync.RWMutex:读写锁的妙用
sync.RWMutex是一种特殊的互斥锁,它允许多个goroutine同时读取共享资源,但只能允许一个goroutine写入共享资源。这对于需要经常读取但很少写入的共享资源非常有用。
以下是一个使用sync.RWMutex的简单示例:
package main
import (
"fmt"
"sync"
)
type Cache struct {
data map[string]string
rwm sync.RWMutex
}
func (c *Cache) Get(key string) (string, bool) {
c.rwm.RLock()
defer c.rwm.RUnlock()
value, ok := c.data[key]
return value, ok
}
func (c *Cache) Set(key, value string) {
c.rwm.Lock()
defer c.rwm.Unlock()
c.data[key] = value
}
func main() {
cache := &Cache{data: make(map[string]string)}
go func() {
for i := 0; i < 100; i++ {
cache.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("value%d", i))
}
}()
go func() {
for i := 0; i < 100; i++ {
value, ok := cache.Get(fmt.Sprintf("key%d", i))
if ok {
fmt.Println("Got value:", value)
}
}
}()
fmt.Scanln()
}
在这个示例中,我们使用sync.RWMutex来保护对cache数据的访问。这样,多个goroutine可以同时读取cache数据,而不会出现数据竞争问题。同时,只有一个goroutine可以写入cache数据,确保数据的完整性。
sync.WaitGroup:协程同步的利器
sync.WaitGroup是一个非常有用的并发同步原语,它可以帮助您等待一组goroutine完成工作。sync.WaitGroup本质上是一个计数器,它记录了需要完成的任务数量。当一个goroutine完成工作时,它会调用sync.WaitGroup的Done()方法,计数器会减一。当计数器为零时,sync.WaitGroup的Wait()方法就会返回,表示所有任务都已完成。
以下是一个使用sync.WaitGroup的简单示例:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println("Hello from goroutine", i)
}(i)
}
wg.Wait()
fmt.Println("All goroutines have finished")
}
在这个示例中,我们使用sync.WaitGroup来等待100个goroutine完成工作。当所有goroutine都完成工作后,sync.WaitGroup的Wait()方法就会返回,并打印出"All goroutines have finished"。
结束语
好了,以上就是我对Go语言中sync包并发同步原语的进一步探讨。希望这些内容对您有所帮助。如果您有任何问题或建议,欢迎在评论区留言。