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]

}