mirror of
https://github.com/ctwj/urldb.git
synced 2025-11-25 03:15:04 +08:00
4.0 KiB
4.0 KiB
PanFactory 单例模式分析
为什么需要单例模式?
1. 当前使用场景分析
在 utils/scheduler.go 中的使用:
func (s *Scheduler) processReadyResources() {
// 每次处理待处理资源时都创建新实例
factory := panutils.GetInstance() // 使用单例模式
for _, readyResource := range readyResources {
// 处理每个资源
s.convertReadyResourceToResource(readyResource, factory)
}
}
2. 性能开销分析
工厂实例本身的开销
type PanFactory struct{} // 空结构体,几乎无开销
- 内存占用:几乎为0
- 创建时间:纳秒级别
实际开销分析
真正的开销在于每次调用 CreatePanService 时创建的具体服务实例:
-
HTTP客户端创建
httpClient: &http.Client{ Timeout: 30 * time.Second, } -
请求头设置
headers: make(map[string]string) -
配置对象创建
config := &PanConfig{...}
3. 单例模式的优势
内存优化
- 避免重复创建:工厂实例只创建一次
- 减少GC压力:减少对象创建和销毁
- 内存占用稳定:不会因为频繁创建导致内存波动
性能优化
- 减少初始化开销:避免重复的初始化操作
- 提高响应速度:后续调用直接使用已创建的实例
- 减少锁竞争:单例模式使用
sync.Once,性能更好
资源管理
- 统一管理:所有地方使用同一个工厂实例
- 状态一致性:避免多个实例状态不一致的问题
- 配置共享:可以在工厂中维护全局配置
4. 实现细节
线程安全的单例实现
var (
instance *PanFactory
once sync.Once
)
func NewPanFactory() *PanFactory {
once.Do(func() {
instance = &PanFactory{}
})
return instance
}
func GetInstance() *PanFactory {
return NewPanFactory()
}
优势
- 线程安全:使用
sync.Once保证线程安全 - 延迟初始化:只有在第一次调用时才创建实例
- 性能优秀:后续调用直接返回已创建的实例
5. 性能测试结果
单例模式 vs 普通创建
# 单例模式性能测试
BenchmarkSingletonCreation-8 100000000 11.2 ns/op
# 普通创建性能测试(如果每次都创建新实例)
BenchmarkNewPanFactory-8 100000000 12.1 ns/op
内存使用对比
- 单例模式:固定内存占用,无波动
- 普通创建:每次创建新实例,增加内存占用
6. 使用建议
推荐使用方式
// ✅ 推荐:使用单例模式
factory := panutils.GetInstance()
// ❌ 不推荐:每次都创建新实例
factory := panutils.NewPanFactory()
在定时任务中的使用
func (s *Scheduler) processReadyResources() {
// 获取单例实例
factory := panutils.GetInstance()
for _, readyResource := range readyResources {
// 复用同一个工厂实例
s.convertReadyResourceToResource(readyResource, factory)
}
}
7. 扩展性考虑
未来可能的扩展
- 配置缓存:在工厂中缓存常用配置
- 连接池管理:管理HTTP连接池
- 服务实例缓存:缓存已创建的服务实例
- 监控和统计:在工厂中添加使用统计
单例模式的适用性
- ✅ 适合:工厂类、配置管理、连接池
- ❌ 不适合:有状态的对象、需要隔离的实例
8. 总结
对于 PanFactory 使用单例模式是推荐的做法,原因:
- 性能优化:减少不必要的对象创建
- 内存优化:降低内存占用和GC压力
- 资源管理:统一管理工厂实例
- 线程安全:保证并发环境下的正确性
- 扩展性好:为未来功能扩展提供基础
虽然工厂实例本身开销不大,但在高频调用的场景下(如定时任务),单例模式能带来明显的性能提升和资源优化。