Go并发编程2-同步控制


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值