golang同步之sync包

时间:2022-01-19 04:37:07

golang中实现并发非常简单,只需在需要并发的函数前面添加关键字"go",但是如何处理go并发机制中不同goroutine之间的同步与通信,golang 中提供了sync包来解决相关的问题,当然还有其他的方式比如channel,原子操作atomic等等,这里先介绍sync包的用法。

sync 包提供了互斥锁这类的基本的同步原语.除 Once 和 WaitGroup 之外的类型大多用于底层库的例程。更高级的同步操作通过信道与通信进行。

type Cond

    func NewCond(l Locker) *Cond

    func (c *Cond) Broadcast()
    func (c *Cond) Signal()
    func (c *Cond) Wait()
type Locker
type Mutex
    func (m *Mutex) Lock()
    func (m *Mutex) Unlock()
type Once
    func (o *Once) Do(f func())
type Pool
    func (p *Pool) Get() interface{}
    func (p *Pool) Put(x interface{})
type RWMutex
    func (rw *RWMutex) Lock() 写锁
    func (rw *RWMutex) RLock()                       读锁
    func (rw *RWMutex) RLocker() Locker
    func (rw *RWMutex) RUnlock()
    func (rw *RWMutex) Unlock()
type WaitGroup
    func (wg *WaitGroup) Add(delta int)
    func (wg *WaitGroup) Done()
    func (wg *WaitGroup) Wait()
    golang中的同步是通过sync.WaitGroup来实现的.WaitGroup的功能:它实现了一个类似队列的结构,可以一直向队列中添加任务,当任务完成后便从队列中删除,如果队列中的任务没有完全完成,可以通过Wait()函数来出发阻塞,防止程序继续进行,直到所有的队列任务都完成为止.
WaitGroup总共有三个方法:
Add(delta int), Done(), Wait()。Add:添加或者减少等待goroutine的数量
Done:相当于Add(-1)
Wait:执行阻塞,直到所有的WaitGroup数量变成0
      程序中需要并发,需要创建多个goroutine,并且一定要等这些并发全部完成后才继续接下来的程序执行.WaitGroup的特点是Wait()可以用来阻塞直到队列中的所有任务都完成时才解除阻塞,而不需要sleep一个固定的时间来等待
    接下来看cond用法,很简单一个goroutine等待另外的goroutine发送通知唤醒。
    然后看Once,它可以保证代码段植段只被执行一次,可以用来实现单例。
   
    用once可以保证上面的oncebody被执行一次,即使被多次调用,内部用一个atmoic int字段标示是否被执行过,和一个锁来实现,具体的可以看go的源码,syc目录下的once.go
    然后说道pool,说白了就是一个对象池,这个类设计的目的是用来保存和复用临时对象,以减少内存分配,降低CG压力。
    Get返回Pool中的任意一个对象。如果Pool为空,则调用New返回一个新创建的对象。如果没有设置New,则返回nil。还有一个重要的特性是,放进Pool中的对象,会在说不准什么时候被回收掉。所以如果事先Put进去100个对象,下次Get的时候发现Pool是空也是有可能的。不过这个特性的一个好处就在于不用担心Pool会一直增长,因为Go已经帮你在Pool中做了回收机制。这个清理过程是在每次垃圾回收之前做的。垃圾回收是固定两分钟触发一次,而且每次清理会将Pool中的所有对象都清理掉!
   
   最后 RWMutex读写锁,RWMutex有两种锁写锁和读锁,用法也有不同,首先读锁可以同时加多个,但是写锁就不行当你试图加第二个写锁时就回导致当前的goroutine或者线程阻塞,但是这里的读锁就不会,那他有什么作用呢。
   当有读锁,试图加写锁会阻塞,当有写锁,试图加读锁时会阻塞,当有读锁,试图加读锁时不会阻塞,这样有什么好处呢,当我们有一种数据读操作远远多于写操作时,当我们读时,如果加mutex或者写锁,会大大影响其他线程,因为我们大多数是读操作,因此如果我们加读锁,就不会影响其他线程的读操作,同时有线程写时也能保证数据的同步。最后一点很重要,不论是读锁还是写锁lock和unlock时一一对应的,unlock前一 定要有lock,就像c++的new和delete,一定要注意。
   下 面看两个例子:来源:点击打开链接
    随便读:注意此时此时不能写。
     写的时候不可读也不可写