请教, sync.Pool 怎么正确缓存一个列表? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
afxcn
V2EX    Go 编程语言

请教, sync.Pool 怎么正确缓存一个列表?

  •  
  •   afxcn
    afxcn 2024-05-09 14:28:09 +08:00 2338 次点击
    这是一个创建于 518 天前的主题,其中的信息可能已经有所发展或是发生改变。

    相关代码如下,我能确保的是,Create 和 Release 是成对出现的;通过下面代码第一次拿到的数据是对的,多次就会出现混乱了。

    func (r *ApplicationRepository) GetApplications(filter string, orderBy string, page int, pageSize int) (*model.ApplicationCollection, error) { var sqlx strings.Builder var args []any sqlx.WriteString("SELECT `id`, `application_name`, `created_at`, `updated_at` ") sqlx.WriteString("FROM `applications` ") sqlx.WriteString("WHERE `status` >= 0 ") if filter != "" { sqlx.WriteString("AND ") if err := utils.SqlFilter(filter, &sqlx, &args, "", r.tryParse); err != nil { return nil, err } sqlx.WriteString(" ") } if orderBy != "" { sqlx.WriteString("ORDER BY ") if err := utils.SqlOrderBy(orderBy, &sqlx, "", r.tryParseKey); err != nil { return nil, err } sqlx.WriteString(" ") } sqlx.WriteString("limit ? offset ?") if pageSize > _maxPageSize { pageSize = _maxPageSize } else if pageSize <= 0 { pageSize = _pageSize } offset := 0 if page > 1 { offset = (page - 1) * pageSize } args = append(args, pageSize, offset) rows, err := query(sqlx.String(), args...) if err != nil { return nil, err } defer rows.Close() applications := model.CreateApplicationCollection() for rows.Next() { application := model.CreateApplication() err := rows.Scan(&application.ID, &application.ApplicationName, &application.CreatedAt, &application.UpdatedAt) if err != nil { return nil, err } *applicatiOns= append(*applications, *application) } return applications, rows.Err() } 
    package model import ( "time" ) // Application model // @Entity tableName="applications" type Application struct { // @PrimaryKey ID uint64 `json:"id"` ApplicationName string `json:"applicationName"` CreatedAt *time.Time `json:"createdAt"` UpdatedAt *time.Time `json:"updatedAt"` } // ApplicationCollection Application list type ApplicationCollection []Application 
    package model import "sync" var ( _applicatiOnPool= sync.Pool{ New: func() any { application := &Application{} return application }} _applicatiOnsPool= sync.Pool{ New: func() any { applications := &ApplicationCollection{} return applications }} ) // CreateApplication return *Application func CreateApplication() *Application { application := _applicationPool.Get().(*Application) return application } func (o *Application) initial() { o.ID = 0 o.ApplicatiOnName= "" o.CreatedAt = nil o.UpdatedAt = nil } func (o *Application) Release() { o.initial() _applicationPool.Put(o) } // CreateApplicationCollection return *ApplicationCollection func CreateApplicationCollection() *ApplicationCollection { applicationCollection := _applicationsPool.Get().(*ApplicationCollection) return applicationCollection } func (o *ApplicationCollection) initial() { *o = (*o)[0:0] } func (o *ApplicationCollection) Release() { for i := 0; i < o.Len(); i++ { (*o)[i].Release() } o.initial() _applicationsPool.Put(o) } 
    第 1 条附言    2024-05-09 22:45:10 +08:00

    我们目前暂时的解决办法是去掉_applicationsPool,不再缓存列表对象。

    代码如下:

    package model import "sync" var ( _applicatiOnPool= sync.Pool{ New: func() any { application := &Application{} return application }} ) // CreateApplication return *Application func CreateApplication() *Application { application := _applicationPool.Get().(*Application) return application } func (o *Application) initial() { o.ID = 0 o.ApplicatiOnName= "" o.CreatedAt = nil o.UpdatedAt = nil } func (o *Application) Release() { o.initial() _applicationPool.Put(o) } // CreateApplicationCollection return *ApplicationCollection func CreateApplicationCollection() *ApplicationCollection { applications := &ApplicationCollection{} return applications } func (o *ApplicationCollection) Release() { for i := 0; i < o.Len(); i++ { (*o)[i].Release() } } 
    第 2 条附言    2024-05-30 10:08:03 +08:00

    append 的 问题,换成make就没问题了。

    错误的写法:

    applications := &ApplicationCollection{}

    *applicatiOns= append(*applications, *application)

    正确的做法:

    applications := make(ApplicationCollection, 0, 10)

    applications[i] = application

    不过在这种场景下使用sync.Pool带来的好处比不上它带来的麻烦,除非是访问并发很高,并且cpu和内存很贵的环境才有必要。

    19 条回复    2024-05-30 17:02:17 +08:00
    MoYi123
        1
    MoYi123  
       2024-05-09 14:33:00 +08:00   2
    建议把代码里无关的东西去掉, 然后搞一个带 main 函数的, 直接能运行的 demo.
    Nazz
        2
    Nazz  
       2024-05-09 14:35:25 +08:00
    你把内存池当缓存用了?
    afxcn
        3
    afxcn  
    OP
       2024-05-09 14:39:29 +08:00
    我自己怀疑问题可能出在:

    *applicatiOns= append(*applications, *application)



    *o = (*o)[0:0]

    这些代码里。
    afxcn
        4
    afxcn  
    OP
       2024-05-09 15:05:27 +08:00
    @Nazz 缓存的是对象,不是数据,主要是在并发高的时候可以少占点内存吧。
    voidmnwzp
        5
    voidmnwzp  
       2024-05-09 16:34:00 +08:00 via iPhone
    sync.pool 是为了减少在堆上分配内存以缓解 gc 的压力,一般我都是在频繁使用的对象或者比较大的对象才会考虑用 pool
    zzhaolei
        6
    zzhaolei  
       2024-05-09 18:27:55 +08:00
    挺好奇为什么 _applicationPool 要用下划线开头?
    dyllen
        7
    dyllen  
       2024-05-09 20:22:42 +08:00
    没怎么看明白,说的混乱是什么意思。
    afxcn
        8
    afxcn  
    OP
       2024-05-09 20:39:11 +08:00
    @dyllen 返回的数据是错误的,就是有些数据丢失,有些重复了。

    @zzhaolei 个人习惯,只要是全局变量都加个下划线 。
    nagisaushio
        9
    nagisaushio  
       2024-05-09 21:00:12 +08:00
    你要保证放回 pool 时对象没有其他引用
    afxcn
        10
    afxcn  
    OP
       2024-05-09 22:56:45 +08:00
    @nagisaushio 也就是说对象不能自己 Release 自己,因为自己还指向自己?

    如果是这样的话,我的整个写法都是错误的了。得好好验证。
    zzhaolei
        11
    zzhaolei  
       2024-05-10 09:50:12 +08:00
    @afxcn 不导出的加一个下划线还行,能区分,导出的全局变量你加吗?不加就不统一,加了就不能导出
    Orlion
        12
    Orlion  
       2024-05-10 10:34:47 +08:00
    确定 ApplicationCollection.Release()调用时机是正确的吗? Release()之后是否还使用到了 ApplicationCollection 或者里面的元素?建议将 Release()的调用代码也发出来。
    afxcn
        13
    afxcn  
    OP
       2024-05-10 10:41:50 +08:00
    @Orlion 用的是这个库: https://github.com/gostartkit/web/blob/master/application.go

    主要代码是这个 #218 - #221 行

    ```go
    if rel, ok := val.(IRelease); ok {
    rel.Release()
    val = nil
    }
    ```
    kfish
        14
    kfish  
       2024-05-10 12:40:55 +08:00
    @zzhaolei 写其他语言带过来的风格吧, 不过 Go 里面还是少见下划线开头的代码
    cannotagreemore
        15
    cannotagreemore  
       2024-05-10 18:38:57 +08:00
    你的 _applicationsPool 这里 New 这个 slice 的地方可以贴一下吗,感觉大概率是这里有点问题
    afxcn
        16
    afxcn  
    OP
       2024-05-10 22:23:08 +08:00
    @cannotagreemore 您指的是这个:type ApplicationCollection []Application ?

    还是这个:

    _applicatiOnsPool= sync.Pool{
    New: func() any {
    applications := &ApplicationCollection{}
    return applications
    }}
    cannotagreemore
        17
    cannotagreemore  
       2024-05-13 10:00:10 +08:00
    这里 new 的时候显式指定一个最大的 Capacity 试一下
    ```
    _applicatiOnsPool= sync.Pool{
    New: func() any {
    applications := &ApplicationCollection{}
    return applications
    }}
    ```
    afxcn
        18
    afxcn  
    OP
       2024-05-30 10:12:23 +08:00
    @cannotagreemore 确实是 Capacity 的问题。
    cannotagreemore
        19
    cannotagreemore  
       2024-05-30 17:02:17 +08:00
    @afxcn 这里是因为你前面的写法没有显示指定最大的 capacity ,默认的 cap=0 ,在 append 操作的时候会触发扩容。其实只需要使用 applications := make(ApplicationCollection, 0, 10) 来初始化就可以了,依然可以使用 append 去进行操作。
    感觉这个场景确实没什么必要针对 slice 使用 sync.Pool 就是了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1265 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 23:52 PVG 07:52 LAX 16:52 JFK 19:52
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86