mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
agents rename
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
# 使用 Channel 的缓冲池
|
||||
|
||||
使用有缓冲 channel 作为空闲列表来复用已分配的缓冲区,避免重复分配。这种"泄漏缓冲"模式使用带 `default` 的 `select` 进行非阻塞操作。
|
||||
|
||||
> **来源**:Effective Go
|
||||
|
||||
```go
|
||||
var freeList = make(chan *Buffer, 100) // 有缓冲 channel 作为空闲列表
|
||||
|
||||
// 客户端:从空闲列表获取缓冲区或分配新的
|
||||
func getBuffer() *Buffer {
|
||||
select {
|
||||
case b := <-freeList:
|
||||
return b // 复用已有缓冲区
|
||||
default:
|
||||
return new(Buffer) // 空闲列表为空;分配新缓冲区
|
||||
}
|
||||
}
|
||||
|
||||
// 服务端:如有空间则将缓冲区归还空闲列表,否则丢弃
|
||||
func putBuffer(b *Buffer) {
|
||||
b.Reset() // 为重用做准备
|
||||
select {
|
||||
case freeList <- b:
|
||||
// 缓冲区已归还空闲列表
|
||||
default:
|
||||
// 空闲列表已满;丢弃缓冲区(GC 会回收)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 工作原理
|
||||
|
||||
1. **非阻塞接收**:客户端尝试从 `freeList` 获取缓冲区。如果为空,`default` 分支运行并分配新缓冲区。
|
||||
2. **非阻塞发送**:服务端尝试归还缓冲区。如果 `freeList` 已满,`default` 分支运行,缓冲区被丢弃等待垃圾回收。
|
||||
3. **有限内存**:channel 容量(100)限制了池中缓冲区的数量,防止无限增长。
|
||||
|
||||
当分配成本较高且缓冲区复用有益,但你不希望在池空或池满时出现阻塞行为时,这种模式非常有用。
|
||||
|
||||
## 何时使用
|
||||
|
||||
- 高频分配相似大小的对象
|
||||
- 分配开销影响性能的代码路径
|
||||
- 需要限制内存使用量的场景
|
||||
|
||||
## 生产环境替代方案
|
||||
|
||||
对于生产代码,考虑使用 `sync.Pool`,它提供类似功能并与垃圾收集器有更好的集成:
|
||||
|
||||
```go
|
||||
var bufferPool = sync.Pool{
|
||||
New: func() any {
|
||||
return new(Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
func getBuffer() *Buffer {
|
||||
return bufferPool.Get().(*Buffer)
|
||||
}
|
||||
|
||||
func putBuffer(b *Buffer) {
|
||||
b.Reset()
|
||||
bufferPool.Put(b)
|
||||
}
|
||||
```
|
||||
|
||||
`sync.Pool` 的优势:
|
||||
- 垃圾收集期间自动清理
|
||||
- 无需管理池大小
|
||||
- 天生线程安全
|
||||
- 高并发下性能更好
|
||||
|
||||
基于 channel 的方式对于理解 Go 的并发原语以及需要更多控制池行为的场景仍然很有价值。
|
||||
Reference in New Issue
Block a user