Sync包简述:
Package sync provides basic synchronization primitives such as mutual exclusion locks. Other than the Once and WaitGroup types, most are intended for use by low-level library > routines. Higher-level synchronization is better done via channels and communication.
Values containing the types defined in this package should not be copied.
Sync包同步提供基本的同步原语,如互斥锁。 除了Once和WaitGroup类型之外,大多数类型都是供低级库例程使用的。 通过Channel和沟通可以更好地完成更高级别的同步。并且此包中的值在使用过后不要拷贝。
Golang中高级的并发可以通过channel来实现,这是golang所倡导的,但是go也提供了锁等相关操作:
1. 同步等待
// WaitGroup:等待组(信号量),起到同步等待的作用
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1) //如果注释掉,会出现短路模式,即不等待
go func(n int) {
fmt.Printf("第%d条下载完毕.\n", n)
wg.Done()
}(i)
}
wg.Wait() //阻塞等待
}
2. 互斥锁
- Mutex:是最简单的一种锁类型,也比较暴力,当一个goroutine获得了Mutex后,其他goroutine就只能乖乖等到这个goroutine释放该Mutex。
func main() {
mutex_foo()
mutex_bar()
}
func mutex_foo() {
var (
share int //公共变量
wg sync.WaitGroup //等待组
m sync.Mutex //互斥锁
)
for i := 0; i < 10000; i++ {
wg.Add(1)
go func() {
m.Lock()
defer m.Unlock()
share++
wg.Done()
}()
}
wg.Wait()
fmt.Println(share)
}
func mutex_bar() {
var (
share int //公共变量
m sync.Mutex //互斥锁
)
go func() {
time.Sleep(time.Second)
fmt.Println(share)
}()
m.Lock()
share = 1
time.Sleep(time.Second * 5)
m.Unlock()
}
3. 读写锁
RWMutex即读写互斥锁,比Mutex相对友好些,是经典的单写多读模型。- 在读锁占用的情况下,会阻止写,但不阻止读,也就是多个goroutine可同时获取读锁(调用RLock方法);
- 而写锁(调用Lock方法)会阻止任何其他goroutine(无论读和写)进来,整个锁由该goroutine独占。
var (
// 逻辑中使用的某个变量
count int
// 与变量对应的使用互斥锁
rwmutex sync.RWMutex
)
func Get() int {
rwmutex.RLock()
defer rwmutex.RUnlock()
return count
}
func Set(c int) {
rwmutex.Lock()
defer rwmutex.Unlock()
count = c
}
func main() {
Set(1)
fmt.Println(Get())
}
4. 单例锁
- 单例锁(
sync.Once)在被第一次被执行后就永久锁定了(可不就相当于受精卵么),整个once对象只被Do一次
func main() {
var once sync.Once
once.Do(func() { fmt.Println("hello 1") })
once.Do(func() { fmt.Println("hello 2") })
go func() {
once.Do(func() {
fmt.Println("hello 3")
})
}()
fmt.Println("over")
time.Sleep(time.Second)
}
// 单例模式
type singleRef map[string]string
var (
once sync.Once
instance singleRef //私有变量
)
func Single() singleRef {
once.Do(func() {
instance = make(singleRef)
})
return instance
}
5. 条件锁
- 条件锁(
sync.NewCond)有单信号(Signal)和广播(Broadcast)两种模式。
// 场景:大爷大妈们超市领大米(先排号,再叫号领礼品)
func main() {
cond := sync.NewCond(new(sync.Mutex))
// 创建30个goroutine,同时进入等待状态
fmt.Println("=================领号牌================")
for i := 0; i < 30; i++ {
go func(x int) {
cond.L.Lock()
defer cond.L.Unlock()
fmt.Printf("%-2d 已领到号\n", x)
cond.Wait() // 暂时阻塞,等待通知吧...
fmt.Printf("%-2d 成功领取领一袋大米\n", x)
}(i)
}
time.Sleep(time.Second)
fmt.Println("=================第一位================")
cond.Signal()
time.Sleep(time.Second)
fmt.Println("=================下一位================")
cond.Signal()
time.Sleep(time.Second * 3)
fmt.Println("================剩余全部===============")
cond.Broadcast()
var quit string
fmt.Scanln(&quit)
}
6. 对象池
- 临时对象池(sync.Pool)中使用
GC,将销毁整个对象池对象。
func main() {
// New:是一个func()interface{}的委托, 用于确定池对象类型
intPool := &sync.Pool{New: func() interface{} { return 0 }}
fmt.Println(intPool.Get().(int))
intPool.Put(1)
intPool.Put(2) //覆盖赋值是无效的
//runtime.GC()
fmt.Println(intPool.Get().(int))
}
7. 同步字典
//https://www.jianshu.com/p/b09853ecd39d
// 读写删改遍历
func main() {
var m sync.Map
m.Store("a", 10) //写
m.Store("a", 11) //改(覆盖)
m.Store("b", 20) //
fmt.Println(m.LoadOrStore("d", 30)) //写或读
fmt.Println(m.LoadOrStore("d", 31)) //(不覆盖)
fmt.Println(m.Load("a")) //读
m.Delete("b") //删
m.Range(func(key, value interface{}) bool { //遍历
fmt.Println(key, value)
return true
})
}
参考:
https://www.jianshu.com/p/4e2922f68991

被折叠的 条评论
为什么被折叠?



