思考下面这个 client-server 配置: 客户端无限循环执行从某个来源(可能是来自网络)接收的数据;数据使用一个 Buffer 类型的缓冲区读取。为了避免过多的分配和释放 buffers,可以保留一个用缓冲通道表示的空闲列表: var freeList = make(chan *Buffer, 100)

    这个可以重复使用的缓冲队列与服务器端共享。当客户端接收数据时,会尝试先从 freeList 获取一个 buffer ;如果 freeList 这个通道是空的,就分配一个新的 buffer。当这个 buffer 被加载完,它会通过 serverChan 发送给服务器端:

    1. var serverChan = make(chan *Buffer)

    下面是客户端代码的算法:

    1. func client() {
    2. for {
    3. var b *Buffer
    4. // 如果 freeList 通道中有 buffer,直接获取;如果没有,就创建一个新的
    5. select {
    6. case b = <-freeList:
    7. // 获取到一个 ,没有做其他事情
    8. default:
    9. // 没有空闲的,所以分配一个新的
    10. b = new(Buffer)
    11. }
    12. loadInto(b) // 从网络去获取下一条信息
    13. serverChan <- b // 发送给服务器端
    14. }
    15. }

    服务器端循环接收每一个客户端的消息,处理它,并尝试将 buffer 返回给共享的 buffers 列表:

    1. func server() {
    2. for {
    3. b := <-serverChan // 等待工作。(等待客户端发送一个 buffer 过来)
    4. process(b)
    5. // 如果就空间,就重用 buffer
    6. select {
    7. case freeList <- b:
    8. // 如果 freeList 有空闲的插槽,就重用 buffer;没有做其他事情
    9. default:
    10. // freeList 已满,只是继续: 会将 buffer 掉落(丢弃)
    11. }
    12. }
    13. }

    但是当 freeList 已满时它不能工作,这种情况下的缓冲区是: 掉落到地上 (因此命名 漏桶算法 )被垃圾回收器回收。