大家好,今天将梳理出的 Go语言并发知识内容,分享给大家。 请多多指教,谢谢。
sync.Condsync.Oncesync.Pool
本章节内容
- sync.Cond
- sync.Once
- sync.Pool
sync.Cond
条件变量
Cond 类型原型
Cond 实现了一个条件变量,用于等待或宣布事件发生时 goroutine 的交汇点。在这个定义中,“事件”是指两个或更多的goroutine之间的任何信号,仅指事件发生了,不包含其他任何信息。 通常,你可能想要在收到某个 goroutine 信号前令其处于等待状态。
MutexRWMutexWait()
NewCond()
func (*Cond) Broadcast()
func (*Cond) Signal()
func (*Cond) Wait()
Wait()Singnal()Broadcast()
Cond 使用
举例1:假设我们有一个固定长度为2的队列,并且我们要将10个元素放入队列中。希望一有空间就能放入,所以在队列中有空间时需要立即通知。
输出
main() goroutine
Broadcast()Broadcast
输出
sync.Cond
sync.Once
一次性执行
Once 类型原型
Once 主要作用是只执行一次处理,在第一次使用后将不可复制。
func (o *Once) Do(f func())
Once 使用
输出
sync.Once
sync.Pool
临时对象池
Pool 类型原型
Pool 是一组可以单独保存和检索的临时对象。存储在池中的任何项目可以在任何时候自动删除而不通知。如果发生这种情况时Pool持有唯一的引用,则可能会释放该项。
Pool 可以安全的被多个 goroutine 同时使用。
Pool 的目的是缓存已分配但未使用的项,以便稍后重用,减轻垃圾收集器的压力。也就是说,它使构建高效的、线程安全的空闲列表变得容易。然而,它并不适用于所有的免费列表。
Pool 适当使用是管理一组临时项,这些临时项在包的并发独立客户端之间共享,并可能被包的并发独立客户端重用。Pool 提供了一种在多个客户端之间摊销分配开销的方法。
sync.Pool
一个很好 Pool 的例子是在 fmt 包中,它维护一个动态大小的临时输出缓冲区存储。存储在负载下伸缩(当许多goroutines正在积极地打印时),在静默时收缩。
注意,作为生存期较短的对象一部分维护的空闲列表不适合用于Pool,因为在这种情况下,开销不会很好地摊销。让这些对象实现它们自己的空闲列表会更有效率。
func (p *Pool) Get() anyGet()Get()Put()Get()
p.Newp.New
func (p *Pool) Put(x any)
Pool 使用
举例1:Pool的主要接口是它的Get方法。 被调用时,Get将首先检查池中是否有可用实例返回给调用者,如果没有,则创建一个新成员变量。使用完成后,调用者调用Put将正在使用的实例放回池中供其他进程使用。
输出
- 调用 Get 方法,将在池中定义 New 函数,因为实例尚未实例化
- 将先前检索到的实例放回池中,这时实例的可用数量为1个
- 执行此调用时,将重新使用先前分配的实例。 New函数不会被调用
举例2:指定分配内存
输出
- 储存了字节切片的指针
- 指向了字节切片的指针
sync.Poolsync.Pool
举例3:Pool 另一种常见情况是预热分配对象缓存,用于必须尽快运行的操作。通过预先加载获取对另一个对象的引用来减少消费者的时间消耗。
正如这个例子所展现的,池模式非常适合于这种需要并发进程,或者构建这些对象可能会对内存产生负面影响的应用程序。
但是,在确定是否应该使用池时有一点需要注意:如果使用池子里东西在内存上不是大致均匀的,则会花更多时间将从池中检索,这比首先实例化它要耗费更多的资源。
因此,在使用 Pool 时,请记住以下几点:
sync.Pool
Pool 特性
最后总结下临时对象池的特性:
Get()Put()
技术文章持续更新,请大家多多关注呀~~
搜索微信公众号,关注我【 帽儿山的枪手 】
书籍[1] sync标准库[2]
参考资料
[1] Go并发编程实战、Concurrency in Go: .
[2] sync标准库: