网站打开慢如何优化,重庆市建设工程信息网更改,以网站建设专业画一幅画,网站设计制作规范简介
在Go提供如何实现对象的缓存池功能#xff1f;常用一种实现方式是#xff1a;sync.Pool, 其旨在缓存已分配但未使用的项目以供以后重用#xff0c;从而减轻垃圾收集器#xff08;GC#xff09;的压力。
快速使用
sync.Pool的结构也比较简单#xff0c;常用的方法…简介
在Go提供如何实现对象的缓存池功能常用一种实现方式是sync.Pool, 其旨在缓存已分配但未使用的项目以供以后重用从而减轻垃圾收集器GC的压力。
快速使用
sync.Pool的结构也比较简单常用的方法有Get、Put
type Pool struct {local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocallocalSize uintptr // size of the local arrayvictim unsafe.Pointer // local from previous cyclevictimSize uintptr // size of victims array// New optionally specifies a function to generate// a value when Get would otherwise return nil.// It may not be changed concurrently with calls to Get.New func() any
}
func (p *Pool) Get() any
func (p *Pool) Put(x any) 接着通过一个简单的例子来看看是如何使用的
package mainimport (fmtsync
)type Object struct {ID int// ...
}func main() {// 1.创建一个sync.Pool对象pool : sync.Pool{New: func() interface{} {fmt.Println(Creating a new object)return Object{}},}// 2.pool.Get()方法从池中获取一个对象。如果池中有可用的对象Get()方法将返回其中一个否则它将返回一个新创建的对象obj : pool.Get().(*Object)// 3.操作对象obj.ID 1// 4.调用pool.Put()方法将对象放回池中pool.Put(obj)objBar : pool.Get().(*Object)fmt.Println(Object ID:, objBar.ID)
}实践应用
在之前的文章中有提到的享元模式设计模式flyweight(享元)的在棋牌游戏的应用的案例。今天我们使用sync.Pool对该方案进行优化。 观察在棋牌游戏的代码虽然解决了每次都要New一个对象的问题但还存在几个优化点:
不能只能缓存特定的棋牌室类型对象 并发安全问题
原来是通过Factory工厂Map实现享元模式截取其中部分代码如下
package design_modeimport fmtvar chessPieceUnit map[int]*ChessPiece{1: {Name: 車,Color: 紅,PositionX: 1,PositionY: 11,},2: {Name: 馬,Color: 黑,PositionX: 2,PositionY: 2,},// 其他棋子
}func NewChessPieceUnitFactory() *ChessBoard {board : ChessBoard{Cards: map[int]*ChessPiece{}}for id : range chessPieceUnit {board.Cards[id] chessPieceUnit[id]}return board
}1.重构Factory
接着我们同sync.Pool修改一下Factory的实现
pool : sync.Pool{New: func() interface{} {fmt.Println(Creating a new object)return NewChessBoard()},
}game1 : pool.Get().(*ChessBoard)
game2 : pool.Get().(*ChessBoard)
fmt.Println(game1)
fmt.Println(game2)
fmt.Println(game1.Cards[0] game2.Cards[0]) 2. 并发安全问题
2.1 修改模型
为了方便观察给每个房间棋牌室增加一个创建时间
type ChessBoard struct {Cards map[int]*ChessPieceTime time.Time
} 2.2 并发测试
启动多个goroutine进行测试
func main() {pool : sync.Pool{New: func() interface{} {fmt.Println(Creating a new object)return NewChessBoard()},}var wg sync.WaitGroupfor i : 0; i 10; i {wg.Add(1)go func(id int) {defer wg.Done()obj : pool.Get().(*ChessBoard)obj.Time time.Now()pool.Put(obj)fmt.Printf(Object ID: %v\n, obj.Time)}(i)}wg.Wait()
} 输出如下:
Creating a new object
Creating a new object
Object ID: 2023-10-22 15:41:50.309343 0800 CST m0.003511901
Object ID: 2023-10-22 15:41:50.3117423 0800 CST m0.005911201
Object ID: 2023-10-22 15:41:50.3117423 0800 CST m0.005911201
Object ID: 2023-10-22 15:41:50.3117423 0800 CST m0.005911201
Object ID: 2023-10-22 15:41:50.3117423 0800 CST m0.005911201
Object ID: 2023-10-22 15:41:50.3117423 0800 CST m0.005911201
Object ID: 2023-10-22 15:41:50.3117423 0800 CST m0.005911201
Object ID: 2023-10-22 15:41:50.3117423 0800 CST m0.005911201
Object ID: 2023-10-22 15:41:50.3117423 0800 CST m0.005911201
Object ID: 2023-10-22 15:41:50.3117423 0800 CST m0.005911201可见在多个goroutine的并发情况下是安全另外可以观察到sync.Pool没有一直【Creating a new object】去New很多棋牌室。
小结
sync.Pool是Go语言标准库中的一个类型它提供了对象的缓存池功能。它的主要用途是存储那些可以被复用的临时对象以便在需要时快速获取而不是每次都进行新的对象分配。且多个 goroutine 同时使用 Pool 是安全的。 本文简述了sync.Pool的基础使用以及了如何使用其对实践棋牌室游戏的案例进行优化过程。
参考
官方doc 设计模式flyweight(享元