欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

golang并發(fā)之使用sync.Pool優(yōu)化性能

 更新時(shí)間:2023年10月24日 09:30:04   作者:jefffff  
在Go提供如何實(shí)現(xiàn)對(duì)象的緩存池功能,常用一種實(shí)現(xiàn)方式是sync.Pool,?其旨在緩存已分配但未使用的項(xiàng)目以供以后重用,從而減輕垃圾收集器(GC)的壓力,下面我們就來(lái)看看具體操作吧

簡(jiǎn)介

在Go提供如何實(shí)現(xiàn)對(duì)象的緩存池功能?常用一種實(shí)現(xiàn)方式是:sync.Pool, 其旨在緩存已分配但未使用的項(xiàng)目以供以后重用,從而減輕垃圾收集器(GC)的壓力。

快速使用

sync.Pool的結(jié)構(gòu)也比較簡(jiǎn)單,常用的方法有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) 

接著,通過(guò)一個(gè)簡(jiǎn)單的例子,來(lái)看看是如何使用的

package main

import (
    "fmt"
    "sync"
)

type Object struct {
    ID int
    // ...
}

func main() {
    // 1.創(chuàng)建一個(gè)sync.Pool對(duì)象
    pool := &sync.Pool{
       New: func() interface{} {
          fmt.Println("Creating a new object")
          return &Object{}
       },
    }
    // 2.pool.Get()方法從池中獲取一個(gè)對(duì)象。如果池中有可用的對(duì)象,Get()方法將返回其中一個(gè);否則,它將返回一個(gè)新創(chuàng)建的對(duì)象
    obj := pool.Get().(*Object)
    // 3.操作對(duì)象
    obj.ID = 1
    // 4.調(diào)用pool.Put()方法將對(duì)象放回池中
    pool.Put(obj)
    objBar := pool.Get().(*Object)
    fmt.Println("Object ID:", objBar.ID)
}

實(shí)踐應(yīng)用

在之前的文章中有提到的享元模式設(shè)計(jì)模式:flyweight(享元)的在棋牌游戲的應(yīng)用的案例。今天我們使用sync.Pool對(duì)該方案進(jìn)行優(yōu)化。 觀察在棋牌游戲的代碼,雖然解決了每次都要New一個(gè)對(duì)象的問(wèn)題,但還存在幾個(gè)優(yōu)化點(diǎn):

  • 不能只能緩存特定的棋牌室類(lèi)型對(duì)象;
  • 并發(fā)安全問(wèn)題

原來(lái)是通過(guò)Factory工廠+Map實(shí)現(xiàn)享元模式,截取其中部分代碼如下

package design_mode

import "fmt"

var chessPieceUnit = map[int]*ChessPiece{
	1: {
		Name:  "車(chē)",
		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.重構(gòu)Factory

接著,我們同sync.Pool修改一下Factory的實(shí)現(xiàn):

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. 并發(fā)安全問(wèn)題

2.1 修改模型

為了方便觀察,給每個(gè)房間(棋牌室)增加一個(gè)創(chuàng)建時(shí)間

type ChessBoard struct {
    Cards map[int]*ChessPiece
    Time  time.Time
} 

2.2 并發(fā)測(cè)試

啟動(dòng)多個(gè)goroutine進(jìn)行測(cè)試

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

可見(jiàn),在多個(gè)goroutine的并發(fā)情況下,是安全,另外可以觀察到,sync.Pool沒(méi)有一直【Creating a new object】去New很多棋牌室。

小結(jié)

sync.Pool是Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的一個(gè)類(lèi)型,它提供了對(duì)象的緩存池功能。它的主要用途是存儲(chǔ)那些可以被復(fù)用的臨時(shí)對(duì)象,以便在需要時(shí)快速獲取,而不是每次都進(jìn)行新的對(duì)象分配。且多個(gè) goroutine 同時(shí)使用 Pool 是安全的。

本文簡(jiǎn)述了sync.Pool的基礎(chǔ)使用,以及了如何使用其對(duì)實(shí)踐棋牌室游戲的案例進(jìn)行優(yōu)化過(guò)程。

以上就是golang并發(fā)之使用sync.Pool優(yōu)化性能的詳細(xì)內(nèi)容,更多關(guān)于go sync.Pool的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語(yǔ)言基礎(chǔ)go fmt命令使用示例詳解

    Go語(yǔ)言基礎(chǔ)go fmt命令使用示例詳解

    這篇文章主要為大家介紹了Go語(yǔ)言基礎(chǔ)go fmt命令的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11
  • Go log庫(kù)的使用示例詳解

    Go log庫(kù)的使用示例詳解

    Go語(yǔ)言?xún)?nèi)置的log庫(kù)提供了基本的日志記錄功能,支持日志的格式化輸出、設(shè)置日志前綴、配置輸出位置等,可以通過(guò)標(biāo)準(zhǔn)logger或創(chuàng)建新的Logger對(duì)象來(lái)使用,log庫(kù)簡(jiǎn)單易用,但功能有限,可能需要配合第三方日志庫(kù)如logrus、zap等來(lái)滿(mǎn)足復(fù)雜需求
    2024-09-09
  • Go?gRPC教程實(shí)現(xiàn)Simple?RPC

    Go?gRPC教程實(shí)現(xiàn)Simple?RPC

    這篇文章主要為大家介紹了Go?gRPC教程實(shí)現(xiàn)Simple?RPC示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • golang框架中跨服務(wù)的最佳通信協(xié)議和工具

    golang框架中跨服務(wù)的最佳通信協(xié)議和工具

    在 go 框架中實(shí)現(xiàn)跨服務(wù)通信的最佳實(shí)踐包括使用 grpc(適用于低延遲高吞吐量)、http 客戶(hù)端(適用于 restful api)和消息隊(duì)列(適用于異步解耦通信),在選擇通信方式時(shí),應(yīng)考慮服務(wù)交互模式、性能要求和部署環(huán)境等因素
    2024-06-06
  • Go語(yǔ)言學(xué)習(xí)技巧之命名規(guī)范

    Go語(yǔ)言學(xué)習(xí)技巧之命名規(guī)范

    最近在學(xué)習(xí)go語(yǔ)言,發(fā)現(xiàn)了不少需要整理的知識(shí)點(diǎn),所以整理下分享出來(lái),下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言學(xué)習(xí)技巧之命名規(guī)范的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-12-12
  • go-micro微服務(wù)JWT跨域認(rèn)證問(wèn)題

    go-micro微服務(wù)JWT跨域認(rèn)證問(wèn)題

    JWT 以 JSON 對(duì)象的形式安全傳遞信息。因?yàn)榇嬖跀?shù)字簽名,因此所傳遞的信息是安全的,這篇文章主要介紹了go-micro微服務(wù)JWT跨域認(rèn)證,需要的朋友可以參考下
    2023-01-01
  • Go語(yǔ)言庫(kù)系列之dotsql詳解

    Go語(yǔ)言庫(kù)系列之dotsql詳解

    這篇文章主要介紹了Go語(yǔ)言庫(kù)系列之dotsql的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 用golang如何替換某個(gè)文件中的字符串

    用golang如何替換某個(gè)文件中的字符串

    這篇文章主要介紹了用golang實(shí)現(xiàn)替換某個(gè)文件中的字符串操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • 利用golang的字符串解決leetcode翻轉(zhuǎn)字符串里的單詞

    利用golang的字符串解決leetcode翻轉(zhuǎn)字符串里的單詞

    這篇文章主要介紹了利用golang的字符串解決leetcode翻轉(zhuǎn)字符串里的單詞,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Golang中文件目錄操作的實(shí)現(xiàn)步驟詳解

    Golang中文件目錄操作的實(shí)現(xiàn)步驟詳解

    在Golang中,文件目錄是指計(jì)算機(jī)文件系統(tǒng)中的文件夾或目錄。目錄是用于組織和存儲(chǔ)文件的一種方式,可以包含文件和其他子目錄,本文主要介紹了Golang中文件目錄操作的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2023-05-05

最新評(píng)論