前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang语言情怀-第17期 Go 语言设计模式-对象池

Golang语言情怀-第17期 Go 语言设计模式-对象池

作者头像
李海彬
发布2021-01-21 17:20:24
6720
发布2021-01-21 17:20:24
举报
文章被收录于专栏:Golang语言社区Golang语言社区

对象池模式

对象池模式,对象被预先创建并初始化后放入对象池中,对象提供者,对象提供者就能利用已有的对象来处理请求,减少对象频繁创建所浪费的资源。例如数据库的连接池等等,基本都是创建后就被放入连接池中,后续的查询请求使用的都是连接池中的对象,从而加快了查询速度(不然每次查询都需要重新创建数据库连接对象,比较浪费)。

一句话解释,对象池模式下,程序在一开始就创建好了一批可用对象供使用

这种模式下,一般有两种角色,即对象池管理者和对象池用户。

对象池管理者负责管理整个对象池,包括初始化对象池,扩充对象池的大小,重置归还对象的状态等等。

对象池用户负责从对象池中获取一个对象,用完之后一般需要归还整这个对象。

一般被放入对象池中的对象包括Socket对象,数据库连接对象(连接池),线程对象(线程池)等等。

五大要素


来看看对象池模式的五大要素:

  • 模式名称:对象池模式
  • 目的(What):在程序刚开始创建一批可用对象供使用。
  • 解决的问题(Why):当我们频繁需要获取一个对象,并且该对象的频繁创建和销毁可能会导致系统性能较高的开销时,使用这种模式,避免对象的重复创建和销毁带来的资源开销。
  • 解决方案(How):一个对象池管理者,负责管理对象;有若干个对象池用户,从对象池中获取对象,用完之后归还。
  • 解决效果:
    • 优点:
    • 缺点:
    1. 如果是一些轻中量级的对象,创建/销毁对象的开销几乎可以忽略不计,没必要使用这种模式,增加程序的复杂度
    2. 并发环境中,多个线程可能(同时)需要获取对象,这个时候必然要引起互斥锁,获取互斥锁(加锁/解锁)的操作产生的开销往往会比创建/销毁对象产生的开销还要大。
    3. 由于一般来说,池中的对象是有限的,这个势必会成为系统可伸缩性的一个瓶颈
    4. 很难正确的设定对象池的大小,如果太小则不起作用,如果太大,则内存占用资源过高。
    5. 复用池中对象,消除创建对象、销毁对象所产生的内存开销、CPU开销以及(若跨网络)产生的网络开销

什么时候使用对象池?

  • 当创建对象的成本很高,且在特定时间对这些对象需求的数量不多时 - 以DB连接为例。创建每个连接对象的成本都很高,因为涉及到网络调用,而且一次可能只需要一个连接。对象池设计模式非常适合这种情况。
  • 当对象是不可变对象时 - 再次以DB连接为例。数据库连接对象是不可变的对象。几乎所有的属性都不需要改变。
  • 出于性能考虑的原因。由于对象池是事先创建好的,它将显著提高应用程序性能

对象池模式的相关对象包括 - 对象池具体结构、池中对象抽象接口、池中对象具体结构、客户:

iPoolObject.go是池中对象抽象接口iPoolObject的代码:

connection.go是池中对象具体结构connection的代码:

pool.go是对象池具体结构pool的代码:

main.go是客户的代码:

结果:

Loan Pool Object with ID: 0

Loan Pool Object with ID: 1

Return Pool Object with ID: 0

Return Pool Object with ID: 1

Go实现对象池模式


Go语言内部有sync.pool包实现了对象池的概念,但是这个设计出来的目的是优化GC的,因为它存储的对象随时都有可能被GC回收掉,具体感兴趣地可以去了解一下该包的用法,这篇文章就不对该包作详细解答了,因为我们的主要目的还是了解对象池模式。因此下面我们会自己实现一个对象池。

场景

当前的场景是我们需要实现一个协程池,我们开始给这个协程池固定一个协程数量,每个协程被用于去执行一项任务(Task),假设当前有1万个任务,我们必不可能用只用一个协程去执行,我们开启若干个协程去不断地轮询执行这些任务

object_pool.go:

代码语言:javascript
复制
package objectPool

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

func TestObjectPool(t *testing.T) {
    // 创建一个拥有10个worker的协程池
    start := time.Now()
    defer func() {
        end := time.Now()
        fmt.Printf("it takes %f seconds\n",end.Sub(start).Seconds())
    }()

    wg := &sync.WaitGroup{}
    p := NewPool(10,wg)

    go p.Run()

    // 创建100个task
    for i := 0; i < 100; i++ {
        wg.Add(1)
        t := NewTask(func() error {
            // 为了显示出协程池的效果,这里每个任务sleep一秒
            time.Sleep(time.Second)
            return nil
        },i)
        p.SetTask(t)
    }

    wg.Wait()
    p.Stop()
}

object_pool_test.go:

代码语言:javascript
复制
package objectPool

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

func TestObjectPool(t *testing.T) {
    // 创建一个拥有10个worker的协程池
    start := time.Now()
    defer func() {
        end := time.Now()
        fmt.Printf("it takes %f seconds\n",end.Sub(start).Seconds())
    }()

    wg := &sync.WaitGroup{}
    p := NewPool(10,wg)

    go p.Run()

    // 创建100个task
    for i := 0; i < 100; i++ {
        wg.Add(1)
        t := NewTask(func() error {
            // 为了显示出协程池的效果,这里每个任务sleep一秒
            time.Sleep(time.Second)
            return nil
        },i)
        p.SetTask(t)
    }

    wg.Wait()
    p.Stop()
}

结果:

代码语言:javascript
复制
=== RUN   TestObjectPool
workerID: 8, the task id 8 was successfully executed
workerID: 2, the task id 4 was successfully executed
...............
...............
workerID: 6, the task id 2 was successfully executed
workerID: 6, the task id 97 was successfully executed
workerID: 2, the task id 99 was successfully executed
it takes 10.030659 seconds
--- PASS: TestObjectPool (10.03s)
PASS

参考资料:

Go实现设计模式系列(8)——Go实现对象池模式

https://blog.csdn.net/lvyibin890/article/details/107765752

go 初始化对象_Go语言设计模式-对象池

https://blog.csdn.net/weixin_42438750/article/details/112099758

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-01-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言情怀 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 对象池模式
    • 五大要素
      • Go实现对象池模式
        • 场景
    相关产品与服务
    数据库
    云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档