GO:复用对象和协程资源

避免频繁分配相同类型临时对象的开销

问题 : 不停地创建临时对象,Golang 运行时的哪些操作会消耗 CPU 资源?

  1. 首先是内存分配。我们不停地创建对象时,就得不断地在堆里面找空闲的内存块,然后进行分配。这就像是在一个大仓库里,每次创建新对象都要重新找地方放,这个过程是很消耗资源的.

  2. 垃圾收集(GC)。要是临时对象很多,那在进行垃圾收集的时候,就需要耗费更多的 CPU 资源去扫描这些对象,看看哪些没用了,然后清理掉。这就像大扫除的时候,如果杂物太多,打扫起来就会更费劲。

问题: 如何避免频繁创建临时对象而产生的内存分配和 GC 开销?

由于我们每次申请的都是同一种类型的对象,也就是 bytes.Buffer。既然这样,像下面的图一样,我们可以在每次用完这个临时对象之后,把它放到一个池子里。等下次要用的时候,就直接从池子里取出来用。这样一来,就不用每次都从堆里重新分配,而且 GC 需要扫描的临时对象也会减少,这就是对象池的思想。
GO 如何创建对象池?

对于对象池,Golang 里有个 sync.Pool 类型来支持

Go 复制代码
var objectPool = sync.Pool{
    New: func() interface{} {
        return &bytes.Buffer{}
    },
}

func WriteBufferWithPool() {
    // 获取临时对象
    buf := objectPool.Get().(*bytes.Buffer)
    // 使用
    buf.Write(data)
    // 将buf对象里面的字段恢复初始值
    buf.Reset()
    // 放回
    objectPool.Put(buf)
}

从 CPU 资源消耗来看,不使用对象池,单次函数调用要 232.2ns,而使用对象池的方式,只要 32.81ns,节约了 86% 左右的 CPU 资源。

从内存消耗来看,使用对象池的方式,平均单次请求从堆中分配的大小和次数直接变成了 0。

问题:协程池:如何避免频繁创建协程的开销?

第一就是内存分配。在 Golang 中,每次创建一个协程,默认都得分配 2KB 的内存空间,而且还要进行初始化。要是不停地创建协程,那就得不停地进行内存分配和初始化,这个过程就需要消耗不少 CPU 资源。

第二就是协程调度。特别是那种 CPU 密集型的应用,如果频繁创建协程,将会导致处于就绪状态、能被 CPU 调度的协程过多。协程调度就会变得很频繁,要知道,协程调度这个过程本身也是会消耗 CPU 资源的。

相关推荐
我的golang之路果然有问题9 小时前
速成GO访问sql,个人笔记
经验分享·笔记·后端·sql·golang·go·database
M1A113 小时前
云原生第一步:Windows Go环境极速配置
后端·go
纪元A梦15 小时前
华为OD机试真题——推荐多样性(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
java·javascript·c++·python·华为od·go·华为od机试题
K8sCat19 小时前
Golang与Kafka的五大核心设计模式
后端·kafka·go
孔令飞20 小时前
Go:终于有了处理未定义字段的实用方案
人工智能·云原生·go
唐僧洗头爱飘柔952720 小时前
(Go Gin)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
后端·golang·go·restful·gin·goweb开发
ん贤1 天前
并发编程【深度解剖】
后端·go·并发
我的golang之路果然有问题1 天前
快速上手GO的net/http包,个人学习笔记
笔记·后端·学习·http·golang·go·net
用户16849371443112 天前
通过 goat 工具对 golang 应用进行增量代码的埋点和监控
go
旅人CS2 天前
用Go语言理解单例设计模式
设计模式·go