思考下面这个 client-server
配置: 客户端无限循环执行从某个来源(可能是来自网络)接收的数据;数据使用一个 Buffer
类型的缓冲区读取。为了避免过多的分配和释放 buffers,可以保留一个用缓冲通道表示的空闲列表: var freeList = make(chan *Buffer, 100)
这个可以重复使用的缓冲队列与服务器端共享。当客户端接收数据时,会尝试先从 freeList 获取一个 buffer ;如果 freeList 这个通道是空的,就分配一个新的 buffer。当这个 buffer 被加载完,它会通过 serverChan
发送给服务器端:
var serverChan = make(chan *Buffer)
下面是客户端代码的算法:
func client() {
for {
var b *Buffer
// 如果 freeList 通道中有 buffer,直接获取;如果没有,就创建一个新的
select {
case b = <-freeList:
// 获取到一个 ,没有做其他事情
default:
// 没有空闲的,所以分配一个新的
b = new(Buffer)
}
loadInto(b) // 从网络去获取下一条信息
serverChan <- b // 发送给服务器端
}
}
服务器端循环接收每一个客户端的消息,处理它,并尝试将 buffer 返回给共享的 buffers 列表:
func server() {
for {
b := <-serverChan // 等待工作。(等待客户端发送一个 buffer 过来)
process(b)
// 如果就空间,就重用 buffer
select {
case freeList <- b:
// 如果 freeList 有空闲的插槽,就重用 buffer;没有做其他事情
default:
// freeList 已满,只是继续: 会将 buffer 掉落(丢弃)
}
}
}
但是当 freeList 已满时它不能工作,这种情况下的缓冲区是: 掉落到地上
(因此命名 漏桶算法
)被垃圾回收器回收。