sync.Pool
sync.Pool 是 Go 语言标准库中提供的一个对象池(Object Pool)实现,用于复用对象以减少内存分配和垃圾回收的开销。对象池可以提高性能,特别是在高并发环境下。
使用 sync.Pool 时,可以将需要复用的对象放入池中,以便后续需要时可以直接从池中获取,而不需要重新创建。当对象被使用完毕后,可以将其放回池中以便复用。
sync.Pool 的重点是重用对象,而不是限制对象的数量。池中的对象数量会根据需求动态增长和缩减,池中对象的生命周期由 GC(垃圾回收器)控制。
当从池中获取对象时,首先会尝试从池中取出复用的对象。如果池中没有可用的对象,那么将会调用 New 方法创建一个新的对象。获取对象时,应该进行类型断言(type assertion)来获取正确的对象类型。
需要注意的是,sync.Pool 并不保证对象在池中的生存时间或复用次数。在高并发环境下,对象可能会被多个 goroutine 同时获取和使用,需要确保对象的状态是安全可复用的。
值得一提的是,对 sync.Pool 的使用并不适用于所有情况。它主要适合于短时间内创建和销毁的对象,而不适用于长时间存储的对象,因为长时间存储对象可能会导致内存过度使用。
总结起来,sync.Pool 是 Go 语言标准库提供的一个对象池实现,用于复用对象以减少内存分配和垃圾回收的开销。它适用于短时间内创建和销毁的对象,并提供了一种高效的对象重用机制。
package _case
import (
"fmt"
"log"
"math/rand"
"sync"
)
func PoolCase() {
target := "192.168.239.149"
pool, err := GetPool(target)
if err != nil {
log.Fatal(err)
}
//创建连接池后,先放入10个连接
for i := 0; i <= 10; i++ {
coon := &Conn{
ID: int64(i),
Target: target,
Status: ON,
}
pool.Put(coon)
}
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 5; j++ {
conn := pool.Get()
fmt.Println(conn.ID)
pool.Put(conn)
}
}()
}
}
连接池
const (
ON = 1
OFF = 0
)
// Conn 链接池
type Conn struct {
ID int64
Target string
Status int
}
func (c *Conn) GetStatus() int {
return c.Status
}
func NewConn(target string) *Conn {
return &Conn{
ID: rand.Int63(),
Target: target,
Status: ON,
}
}
ConnPool 创建Pool对象
// ConnPool 创建Pool对象
type ConnPool struct {
sync.Pool
}
```
GetPool 在链接池取出
```go
// GetPool 在链接池取出
func GetPool(target string) (*ConnPool, error) {
return &ConnPool{
Pool: sync.Pool{
New: func() any { //初始化连接
return NewConn(target)
},
},
}, nil
}
Get 获取连接池,返回连接
// Get 获取连接池,返回连接
func (c ConnPool) Get() Conn {
conn := c.Pool.Get().(*Conn)
if conn.GetStatus() == OFF { //如果连接池被关闭
conn = c.Pool.New().(*Conn)
}
return conn
}
Put 释放连接
// Put 释放连接
func (c ConnPool) Put(conn Conn) {
if conn.GetStatus() == OFF {
return
}
c.Pool.Put(conn)
}
注意事项
1. 用户缓存一些创建成本较高, 使用比较频繁的对象
2. Pool的长度默认为机器CPU线程数
3. 存储在Pool中的对象随时都可能在不被通知的情况下回收
4. 没有什么创建成本的对象不建议使用对象池
sync.Once
sync.Once 是 Go 语言标准库中提供的一种同步原语,用于保证某个操作只执行一次。通常用于在多个 goroutine 之间共享一个全局或者一次性初始化的资源。
sync.Once 类型具有一个 Do 方法,该方法接收一个函数作为参数并执行该函数。第一次调用 Do 方法时,会执行传入的函数;而后续的调用则会被忽略,不再执行该函数。
sync.Once 内部通过一个互斥锁和一个标志位实现。在第一次调用 Do 方法时,goroutine 会获取到互斥锁并检查标志位。如果标志位为 false,表示该操作尚未执行,则执行传入的函数并将标志位设置为 true;如果标志位为 true,则直接跳过函数的执行。无论是函数执行还是跳过,最后都会释放互斥锁,并且后续的调用都不会再获取互斥锁。
sync.Once 的典型用途是进行一次性资源初始化。例如,可以使用 sync.Once 来确保只有一个 goroutine 对某个全局变量进行初始化,而后续的读取操作可以直接使用该已初始化的值,而无需重复初始化。
需要注意的是,被传入 Do 方法的函数可能会被调用多次,但是 sync.Once 会确保只有第一次调用会执行实际的函数体。
总结而言,sync.Once 是 Go 语言标准库提供的一种同步原语,用于保证某个操作只执行一次。它适用于在多个 goroutine 之间共享全局或一次性初始化的资源,并提供了一种高效的初始化机制
使用sync.Once函数只被调用一次
package _case
import (
"fmt"
"sync"
)
type onceMap struct {
sync.Once
data map[string]int
}
func (m *onceMap) LoadData() {
m.Do(func() {
list := []string{"A", "B", "C", "D"}
for _, item := range list {
_, ok := m.data[item]
if !ok {
m.data[item] = 0
}
m.data[item] += 1
}
}) //只调用一次该函数
}
调用10次函数只得到一次结果
func OnceCase() {
o := &onceMap{
data: make(map[string]int),
}
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
o.LoadData()
}()
}
wg.Wait()
fmt.Println(o.data) //map[A:1 B:1 C:1 D:1]
}