理解 Go 语言的池Pool

        Go 是一种有自动垃圾回收机制的编程语言,采用三色并发标记算法标记对象并回收。和其他没有自动垃圾回收机制的编程语言不同,使用 Go 语言创建对象时,我们没有回收/释放的心理负担,想创建对象就创建,想用对象就用。

        但是,如果想使用 Go 语言开发一个高性能的应用程序,就必须考虑垃圾回收给性能带来的影响,毕竟 Go 的自动垃圾回收机制有一个STW(stop-the-world,程序暂停)的时间,而且在堆上大量地创建对象,也会影响垃圾回收标记的时间。所以,我们在做性能优化时,通常会采用对象池的方式,把不用的对象回收起来,避免被垃圾回收,这样使用时就不必在堆上重新创建对象了。

        不仅如此,像数据库连接、TCP 的长连接等,这些连接的创建也是一个非常耗时的操作。如果每次使用时都创建一个新的连接,则很可能整个业务的很多时间都花在了创建连接上。所以,如果能把这些连接保存下来,避免每次使用时都重新创建,则不仅可以大大减少业务的耗时,还能提高应用程序的整体性能。 

        这种模式被称为对象池设计模式(object pool pattern) 。一个对象池包含一组已经初始化过且可以重复使用的对象,池的用户可以从池子中获得对象,对其进行操作处理,并在不需要的时候归还给池子,而非直接销毁它。

        若初始化对象的代价很高,且经常需要实例化对象,但实例化的对象数量较少,那么使用对象池可以显著提升性能。从池子中获得对象的时间是可预测的且时间花费较少,而新建一个实例所需的时间是不确定的,可能时间花费较多。

        Go标准库中提供了一个通用的 Pool 数据结构,也就是 sync.Pool,我们使用它可以创建池化的对象。

1. sync.Pool 的使用方法

        首先,我们来介绍 Go 标准库中提供的 sync.Pool 数据类型。

        sync.Pool 数据类型用来保存一组可独立访问的 “临时” 对象。请注意这里加引号的 “临时” 两个字,它说明了 sync.Pool 这个数据类型的特点--其池化的对象会在未来某个时候被毫无征兆地移除。而且,如果没有别的对象引用这个要被移除的对象,该对象就会被垃圾回收。

        因为 Pool 可以有效地减少对新对象的申请,从而提高程序性能,所以 Go 内部库中也用到了 sync.Pool。比如 fmt 包,它会使用一个动态大小的 buffer 池做输出缓存,当大量的 goroutine 并发输出的时候,就会创建比较多的 buffer ,并且在不需要的时候被回收。

有两个知识点需要记住:

  • sync.Pool 本身就是线程安全的,多个 goroutine 可以并发地调用它的方法存取对象。
  • sync.Pool 不可在使用之后再复制使用。

        这个数据类型提供了三个对外的方法:New、Get 和 Put。

1. New:创建对象

        这里的 New 不是创建 Pool 类型的对象的方法,而是 Pool 对象创建其池化对象的方法。因为只有定义了创建池化对象的方法,它才能在需要的时候创建对像。

        Pool struct 包含一个 New 字段,这个字段的类型是函数 func() interface{ }。当调用 Pool 的 Get 方法从池中获取对象时,如果没有更多空闲的对象可用&#x

  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mindfulness code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值