goroutineGosyncMutexRWMutexWaitGroupOnceCondsyncsyncPoolMap

sync.Mutex

sync.Mutexsync
mutex := &sync.Mutex{}

mutex.Lock()
// Update共享变量 (比如切片,结构体指针等)
mutex.Unlock()
sync.Mutexsync

sync.RWMutex

sync.RWMutexsync.MutexLockUnLocksync.LockerRLockRUnlock
mutex := &sync.RWMutex{}

mutex.Lock()
// Update 共享变量
mutex.Unlock()

mutex.RLock()
// Read 共享变量
mutex.RUnlock()
sync.RWMutexsync.Mutex

通过基准测试来比较这几个方法的性能:

BenchmarkMutexLock-4       83497579         17.7 ns/op
BenchmarkRWMutexLock-4     35286374         44.3 ns/op
BenchmarkRWMutexRLock-4    89403342         15.3 ns/op
sync.RWMutexsync.Mutexsync.RWMutexLock()Unlock()
sync.RWMutex

sync.WaitGroup

sync.WaitGroupgoroutinegoroutine
sync.WaitGroup0Wait()Wait()goroutine0
Add(int)Done()1AddDone()Add(-1)
goroutine
wg := &sync.WaitGroup{}

for i := 0; i < 8; i   {
  wg.Add(1)
  go func() {
    // Do something
    wg.Done()
  }()
}

wg.Wait()
// 继续往下执行...
goroutinewg.Add(1)wgforwg.Add(8)
goroutinewg.Done()wg
main goroutinegoroutinewg.Done()0

sync.Map

sync.MapGomap
Store(interface {},interface {})Load(interface {}) interface {}Delete(interface {})LoadOrStore(interface {},interface {}) (interface {},bool)maptrueRange
m := &sync.Map{}

// 添加元素
m.Store(1, "one")
m.Store(2, "two")

// 获取元素1
value, contains := m.Load(1)
if contains {
  fmt.Printf("%s\n", value.(string))
}

// 返回已存value,否则把指定的键值存储到map中
value, loaded := m.LoadOrStore(3, "three")
if !loaded {
  fmt.Printf("%s\n", value.(string))
}

m.Delete(3)

// 迭代所有元素
m.Range(func(key, value interface{}) bool {
  fmt.Printf("%d: %s\n", key.(int), value.(string))
  return true
})

上面的程序会输出:

one
three
1: one
2: two
Rangefunc(key,value interface {})boolfalsefalseO(n)
sync.Mapmapsync.Mutex
mapgoroutinegoroutinegoroutinesync.Map

sync.Pool

sync.Pool
Get() interface{}Put(interface{})
pool := &sync.Pool{}

pool.Put(NewConnection(1))
pool.Put(NewConnection(2))
pool.Put(NewConnection(3))

connection := pool.Get().(*Connection)
fmt.Printf("%d\n", connection.id)
connection = pool.Get().(*Connection)
fmt.Printf("%d\n", connection.id)
connection = pool.Get().(*Connection)
fmt.Printf("%d\n", connection.id)

输出:

1
3
2
Get()
sync.Pool
pool := &sync.Pool{
  New: func() interface{} {
    return NewConnection()
  },
}

connection := pool.Get().(*Connection)
Get()pool.New

那么什么时候使用sync.Pool?有两个用例:

第一个是当我们必须重用共享的和长期存在的对象(例如,数据库连接)时。第二个是用于优化内存分配。

sync.Pooldefersync.Pool
func writeFile(pool *sync.Pool, filename string) error {
    buf := pool.Get().(*bytes.Buffer)

  defer pool.Put(buf)

    // Reset 缓存区,不然会连接上次调用时保存在缓存区里的字符串foo
    // 编程foofoo 以此类推
    buf.Reset()

    buf.WriteString("foo")

    return ioutil.WriteFile(filename, buf.Bytes(), 0644)
}

sync.Once

sync.Oncegoroutine
once := &sync.Once{}
for i := 0; i < 4; i   {
    i := i
    go func() {
        once.Do(func() {
            fmt.Printf("first %d\n", i)
        })
    }()
}
Do(func ())

sync.Cond

sync.Condsyncgoroutinegoroutinesync.Condsync.Lockersync.Mutexsync.RWMutex
cond := sync.NewCond(&sync.Mutex{})

然后,让我们编写负责显示切片的第一个元素的函数:

func printFirstElement(s []int, cond *sync.Cond) {
    cond.L.Lock()
    cond.Wait()
    fmt.Printf("%d\n", s[0])
    cond.L.Unlock()
}
cond.Lcond.Wait()goroutine
main goroutinesync.CondprintFirstElementget()s[0]
s := make([]int, 1)
for i := 0; i < runtime.NumCPU(); i   {
    go printFirstElement(s, cond)
}

i := get()
cond.L.Lock()
s[0] = i
cond.Signal()
cond.L.Unlock()
goroutinegoroutines[0]
Go
不要通过共享内存进行通信;而是通过通信共享内存。
channelget()sync.CondSignal()Broadcast()
i := get()
cond.L.Lock()
s[0] = i
cond.Broadcast()
cond.L.Unlock()
channelgoroutinechannelchannel
当一个channel被关闭后,channel中已经发送的数据都被成功接收后,后续的接收操作将不再阻塞,它们会立即返回一个零值。
sync.Cond

推荐阅读

学会使用context取消goroutine执行的方法

使用SecureCookie实现客户端Session管理

Go Web编程--解析JSON请求和生成JSON响应

到此这篇关于“Go语言sync包的应用详解”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
想系统学习GO语言(Golang
Goroutine 的同步(第三部分)
Go 语言包管理机制深入分析
go语言和python哪个难
golang 深入浅出之 goroutine 理解
1.14 Go语言工程结构详述
go语言和php的区别是什么?
[Go学习] 并发控制之WaitGroup计数信号量
初识GO语言以及GO语言安装及环境搭建
Go语言学习3----Go语言特色