golang sync 包

sync.Pool 的分享,关于适用场景:

当多个 goroutine 都需要创建同⼀个对象的时候,如果 goroutine 数过多,导致对象的创建数⽬剧增,进⽽导致 GC 压⼒增大。形成 “并发⼤-占⽤内存⼤-GC 缓慢-处理并发能⼒降低-并发更⼤”这样的恶性循环。 在这个时候,需要有⼀个对象池,每个 goroutine 不再⾃⼰单独创建对象,⽽是从对象池中获取出⼀个对象(如果池中已经有的话)。

因此关键思想就是对象的复用,避免重复创建、销毁,下面我们来看看如何使用。
所以,sync.pool 的作用一句话描述就是,复用临时对象,以避免频繁的内存分配和回收,从而减少 GC 压力。

sync.Pool 是协程安全的,这对于使用者来说是极其方便的。使用前,设置好对象的 New 函数,用于在 Pool 里没有缓存的对象时,创建一个。之后,在程序的任何地方、任何时候仅通过 Get()、Put() 方法就可以取、还对象了。


sync.Cond 使用
Golang 的 sync 包中的 Cond 实现了一种条件变量,可以使用在多个Reader等待共享资源 ready 的场景(如果只有一读一写,一个锁或者channel就搞定了)。

Cond的汇合点:多个goroutines等待、1个goroutine通知事件发生。

比较适合任务调用场景,一个 Master goroutine 通知事件发生,多个 Worker goroutine 在资源没准备好的时候就挂起,等待通知。

// 创建Cond
cond := sync.NewCond(new(sync.Mutex))
// 挂起goroutine
cond.L.Lock()
cond.Wait()
// 唤醒一个
cond.Signal()
// 唤醒所有
cond.Broadcast()

基本使用大概是需要等待的时候通过 Wait() 将 Goroutine 挂起,资源准备好的时候再通过 Signal() 或者 Broadcast() 将挂起中的 Goroutine 唤醒。

package main

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

func main() {
    var (
        locker sync.Mutex
        cond   = sync.NewCond(&locker)
        wg     sync.WaitGroup
    )

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(number int) {
            // wait()方法内部是先释放锁 然后在加锁 所以这里需要先 Lock()
            cond.L.Lock()
            defer cond.L.Unlock()
            cond.Wait() // 等待通知,阻塞当前 goroutine

            fmt.Printf("g %v ok~ \n", number)
            wg.Done()
        }(i)
    }

    for i := 0; i < 5; i++ {
        // 每过 100毫秒 唤醒一个 goroutine
        cond.Signal()
        time.Sleep(time.Millisecond * 100)
    }
    time.Sleep(time.Millisecond * 100)

    // 剩下5个 goroutine 一起唤醒
    cond.Broadcast()
    fmt.Println("Broadcast...")
    wg.Wait()
}

func add(a, b int) int {
    return a + b
}

func Fib(n int) int {
    if n < 2 {
        return n
    }
    return Fib(n-1) + Fib(n-2)
}

你可能感兴趣的:(golang)