1

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

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

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

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

pool就是对象缓存池,用来减少堆上内存的反复申请和释放的。因为 golang 的内存是用户触发申请,runtime 负责回收。如果用户申请内存过于频繁,会导致runtime 的回收压力陡增,从而影响整体性能。

有了pool 之后就不一样了,对象申请先看池子里有没有现成的,有就直接返回。释放的时候内存也不是直接归还,而是放进池子而已。适时释放。这样就能极大的减少申请内存的频率。从而减少gc压力。


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)
}

goper
413 声望26 粉丝

go 后端开发


« 上一篇
GoTests 使用