美文网首页
Golang学习笔记-sync

Golang学习笔记-sync

作者: 土豆吞噬者 | 来源:发表于2019-12-17 23:26 被阅读0次

Mutex

  • sync.Mutex为互斥锁,同一时间只能有一个goroutine获得互斥锁。
  • 使用Lock()加锁,Unlock()解锁,加锁前不能解锁,加锁后不能继续加锁。
  • 已经锁定的 Mutex 并不与特定的 goroutine 相关联,可以利用一个 goroutine 对其加锁,再利用其他 goroutine 对其解锁。
  • 适用于同一时间只能有一个goroutine访问资源的场景。

下面的代码如果不使用Mutex,输出的会是1 1 2 2 3 3而不是1 2 3 1 2 3。

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    mutex sync.Mutex
)

func print123(){
    mutex.Lock()
    defer mutex.Unlock()
    for i:=0;i<3;i++{
        fmt.Println(i+1)
        time.Sleep(time.Millisecond*100)
    }
}

func main(){
    go print123()
    go print123()
    time.Sleep(time.Second*5)
}

RWMutex

  • sync.RWMutex为读写锁,同一时间可以有多个goroutine获得读锁或者一个goroutine获得写锁。
  • 使用Lock()加写锁,Unlock()解写锁,RLock()加读锁,RUnlock()解读锁,读锁可以加多个,解读锁的次数不能多于加读锁的次数。
  • 适用于同一时间可以有多个goroutine对资源进行读操作或一个goroutine对资源进行写操作的场景。
  • 读少写多的情况下使用Mutex,其它情况下RWMutex性能更好。

Map

Go内建的map不是线程安全的,所以之前都会使用加锁的方式控制对map的并发访问,而在新版本中可以使用sync.Map代替map+RWMutex,sync.Map相比后者有更好的性能,下面是sync.Map的基本使用方法:

package main

import (
    "fmt"
    "sync"
)

var (
    players sync.Map
)



func main(){
    //设置key对应的value
    players.Store("xiao ming",100)
    //返回key对应的valuee,value不存在时返回nil,false
    if value,ok:=players.Load("xiao ming");ok{
        fmt.Println(value)
    }else{
        fmt.Println("key:xiao ming does not exist!")
    }
    //如果key对应的value存在,则返回value和true
    //如果key对应的value不存在,则将key对应的value设置为参数中的value,并返回value和false
    if value,ok := players.LoadOrStore("xiao hong",120);ok{
        fmt.Println(value)
    }else{
        fmt.Println("key:xiao hong does not exist,store it!")
    }
    //遍历map,函数返回false时停止遍历
    players.Range(func(key,value interface{})bool{
        fmt.Println(key,value)
        return true
    })
    //删除key对应的value
    players.Delete("xiao hong")
}

atomic

sync.atomic提供了对几种简单类型进行原子操作的函数(LoadXXX,StoreXXX),相比Mutex/RWMutex,其性能更好,临界区也更小。

Once

sync.Once可以使函数只被调用一次:

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    closeOnce sync.Once
)

func closeSomething(){
    fmt.Println("close object")
}

func invokeClose(){
    closeOnce.Do(closeSomething)
}

func main() {
    go invokeClose()
    go invokeClose()
    time.Sleep(time.Second*5)
}

WaitGroup

sync.WaitGroup常用来等待其它goroutine结束,Add()增加计数器,Done()减少计数器,Wait()会一直阻塞当前goroutine直到计数器为0。

常见用法为调用Add()增加计数器,启动goroutine,调用Wait()等待goroutine结束,goroutine结束时调用Done()减少计数器。

需要注意的是不能让计数器为负数,否则会报错。另外sync.WaitGroup是值类型,所以在传值的时候需要用指针。

package main

import (
    "sync"
    "time"
)

var (
    waitGroup = &sync.WaitGroup{}
)

func doSomething(){
    defer waitGroup.Done()
    time.Sleep(time.Second*5)
}



func main() {
    waitGroup.Add(1)
    go doSomething()
    waitGroup.Wait()
}

相关文章

网友评论

      本文标题:Golang学习笔记-sync

      本文链接:https://www.haomeiwen.com/subject/xyfynctx.html