Go并发:使用sync.Pool来性能优化

这篇具有很好参考价值的文章主要介绍了Go并发:使用sync.Pool来性能优化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

在Go提供如何实现对象的缓存池功能?常用一种实现方式是:sync.Pool, 其旨在缓存已分配但未使用的项目以供以后重用,从而减轻垃圾收集器(GC)的压力。

快速使用

sync.Pool的结构也比较简单,常用的方法有Get、Put

type Pool struct {
    local     unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
    localSize uintptr        // size of the local array

    victim     unsafe.Pointer // local from previous cycle
    victimSize 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 main

import (
    "fmt"
    "sync"
)

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_mode

import "fmt"

var 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]*ChessPiece
    Time  time.Time
} 

2.2 并发测试

启动多个goroutine进行测试

func main() {
    pool := &sync.Pool{
       New: func() interface{} {
          fmt.Println("Creating a new object")
          return NewChessBoard()
       },
    }
    var wg sync.WaitGroup
    for 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 m=+0.003511901
Object ID: 2023-10-22 15:41:50.3117423 +0800 CST m=+0.005911201
Object ID: 2023-10-22 15:41:50.3117423 +0800 CST m=+0.005911201
Object ID: 2023-10-22 15:41:50.3117423 +0800 CST m=+0.005911201
Object ID: 2023-10-22 15:41:50.3117423 +0800 CST m=+0.005911201
Object ID: 2023-10-22 15:41:50.3117423 +0800 CST m=+0.005911201
Object ID: 2023-10-22 15:41:50.3117423 +0800 CST m=+0.005911201
Object ID: 2023-10-22 15:41:50.3117423 +0800 CST m=+0.005911201
Object ID: 2023-10-22 15:41:50.3117423 +0800 CST m=+0.005911201
Object ID: 2023-10-22 15:41:50.3117423 +0800 CST m=+0.005911201

可见,在多个goroutine的并发情况下,是安全,另外可以观察到,sync.Pool没有一直【Creating a new object】去New很多棋牌室。

小结

sync.Pool是Go语言标准库中的一个类型,它提供了对象的缓存池功能。它的主要用途是存储那些可以被复用的临时对象,以便在需要时快速获取,而不是每次都进行新的对象分配。且多个 goroutine 同时使用 Pool 是安全的。
本文简述了sync.Pool的基础使用,以及了如何使用其对实践棋牌室游戏的案例进行优化过程。

参考

官方doc
设计模式:flyweight(享元文章来源地址https://www.toymoban.com/news/detail-719813.html

到了这里,关于Go并发:使用sync.Pool来性能优化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Go】Go语言并发编程:原理、实践与优化

    在当今的计算机世界,多核处理器和并发编程已经成为提高程序执行效率的关键。Go语言作为一门极富创新性的编程语言,凭借其强大的并发能力,在这方面表现出色。本文将深入探讨Go语言并发编程的原理,通过实际代码示例展示其应用,并讨论可能的优化策略。 在了解G

    2024年02月10日
    浏览(59)
  • Go RWMutex:高并发读多写少场景下的性能优化利器

    原创文章,如需转载请联系 作者:陈明勇 公众号:Go技术干货 在这篇文章 Go Mutex:保护并发访问共享资源的利器 中,主要介绍了 Go 语言中互斥锁 Mutex 的概念、对应的字段与方法、基本使用和易错场景,最后基于 Mutex 实现一个简单的协程安全的缓存。而本文,我们来看看另

    2023年04月09日
    浏览(43)
  • Go并发编程 Goroutine、Channel、Select、Mutex锁、sync、Atomic等

    本文所有实例代码运行go版本: go version go1.18.10 windows/amd64 串行:所有任务一件一件做,按照事先的顺序依次执行,没有被执行到的任务只能等待。最终执行完的时间等于各个子任务之和。 并发:是以交替的方式利用 等待 某个任务的时间来处理其他任务计算逻辑,在计算机

    2024年02月07日
    浏览(52)
  • GO语言基础笔记(八):高级特性与性能优化

             目录 反射(Reflection) 反射概念 反射的关键概念 反射的常见用途 代码示例 1. 检查类型和值 2. 修改变量值 3. 调用函数 4. 结构体反射 并发模式(Concurrency Patterns) 1. Worker Pool 模式 工作原理 在代码中的体现 2. Pipeline 模式 工作原理 在代码中的体现 3. Fan-in/Fan-out

    2024年02月02日
    浏览(58)
  • Go学习圣经:Go语言实现高并发CRUD业务开发

    现在 拿到offer超级难 ,甚至连面试电话,一个都搞不到。 尼恩的技术社群中(50+),很多小伙伴凭借 “左手云原生+右手大数据”的绝活,拿到了offer,并且是非常优质的offer, 据说年终奖都足足18个月 。 第二个案例就是:前段时间,一个2年小伙伴希望涨薪到18K, 尼恩把

    2024年02月11日
    浏览(53)
  • 【Golang】go编程语言适合哪些项目开发?

    前言 在当今数字化时代,软件开发已成为各行各业的核心需求之一。 而选择适合的编程语言对于项目的成功开发至关重要。 本文将重点探讨Go编程语言适合哪些项目开发,以帮助读者在选择合适的编程语言时做出明智的决策。 Go 编程语言适合哪些项目开发? Go是由Google开发

    2024年02月04日
    浏览(80)
  • Go语言中的Pool

    Go语言中的pool是一个资源池,它可以存储一定数量的资源,这些资源可以被多个goroutine共享。Pool可以提高资源的利用率,减少资源的创建和销毁带来的开销。 Pool的实现原理很简单,它使用一个队列来存储资源。当一个goroutine需要使用资源时,它可以从队列中获取一个资源。

    2024年01月17日
    浏览(40)
  • Go语言Sync包

    在处理 goroutine 时,确保它们不会同时访问资源是非常重要的,而 mutex 可以帮助我们做到这一点。 1.1 sync.Mutex 看看这个简单的例子,我没有使用互斥锁来保护我们的变量 a: 此代码的结果是不可预测的,如果幸运的话,您可能会得到 500,但通常结果会小于 500。现在,让我们

    2024年02月16日
    浏览(44)
  • 【MySQL自身的性能优化】InnoDB 的 Buffer Pool

    有近俩个来月没有写博客了,也不知道自己在瞎忙活什么。之前我有写过一篇关于 MySQL 的内存池一篇博客 InnoDB体系架构之内存池(buffer pool),那是看楠哥视频后总结出来的。然后现是看了《MySQL 是怎样运行的》一书,也可能是基础相比之前要好了些,理解的要好点了吧,就

    2024年01月20日
    浏览(41)
  • 仅三天,我用 GPT-4 生成了性能全网第一的 Golang Worker Pool,轻松打败 GitHub 万星项目

    激动的心,颤抖的手,我用 DevChat[1] 白嫖 GPT-4 写下了这辈子写过的最炫酷,最艺术的一千行代码! 我用 Golang 写了一个强大又易用的 Worker Pool 程序,起名 GoPool[2]! 目测功能完备,性能很好,简洁易用,代码优雅,文档齐全…… 谦虚,冷静,克制,别让人逮到机会喷……

    2024年01月18日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包