[go语言]一种自适应资源分配器的实现

stevewang · · 2230 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

  在上一篇博文《利用缓冲信道来实现网游帐号验证消息的分发和等待中提到提到利用缓冲信道来实现数据包的分发和等待,并给出了一个原型实现。但是其中的缓冲信道有一个不足,即只能允许一定数量的goroutine在同时使用SendAndReceive函数等待消息的分发;如果有更多的goroutine需要等待消息,则必须等其他goroutine获得消息并释放信道以后自己才能发送数据包并等待回应。这个不足在高并发时限制了系统的吞吐量。
    为了解决这个问题,本文提供一种自适应的信道分配器的实现作为一种解决方案。因为信道也可以换成别的资源,所以认为它本质上是一种资源分配器。这个自适应资源分配器的原理是:
    1.预先分配一定数量的资源放到缓冲信道(缓冲池)里,以便在申请资源时能够快速获得资源
    2.如果申请资源时缓冲池为空,则动态分配资源
    3.回收资源时,直接把资源放入缓冲池;如果缓冲池满则放入一个备用缓冲池,备用缓冲池是一个数组,所以把资源放入备用缓冲池的动作可以立即完成而不会无限等待。
    4.资源分配器自身有一个goroutine在运行,如果检测到备用缓冲池有资源,则把资源移入缓冲池。
    5.当并发数越来越高时,预分配用的资源(即缓冲池和备用缓冲池中的资源)也会越来越多,从而实现了某种程度上的自适应性。
    6.因为使用了信道作为通信手段,因此申请资源和释放资源的操作都是支持并发的。

    代码实现了一个资源分配器Pool,资源分配器使用NewPool函数创建,资源的申请和释放可以分别通过AllocFree函数完成。具体代码如下所示:

// 这里的资源是chan []byte,因此缓冲池的类型就是chan chan []byte
type Pool struct {
    chch chan chan []byte
    back chan chan []byte
    exit chan bool
}
func NewPool(count int) *Pool {
    p := new(Pool)
    p.back = make(chan chan []byte, count)
    p.chch = make(chan chan []byte, count)
    for i := 0; i < count; i++ {
        p.chch <- make(chan []byte, 1)
    }
    p.exit = make(chan bool)
    go p.run()
    return p
}
func (p *Pool) Alloc() chan []byte {
    select {
    case ch := <-p.chch:
        return ch
    default:
        break
    }
    return make(chan []byte, 1)
}
func (p *Pool) Free(ch chan []byte) {
    select {
    case p.chch <- ch:
        return
    default:
        p.back <- ch
    }
}
func (p *Pool) Close() {
    if p.exit != nil {
        close(p.exit)
        p.exit = nil
    }
}
func (p *Pool) run() {
    var chs []chan []byte
    var chch chan chan []byte
    var next chan []byte
    for {
        select {
        case <-p.exit:
            return
        case ch := <-p.back:
            if chch == nil {
                chch = p.chch
                next = ch
            } else {
                chs = append(chs, ch)
            }
        case chch <- next:
            if len(chs) == 0 {
                chch = nil
                next = nil
            } else {
                next = chs[len(chs)-1]
                chs = chs[:len(chs)-1]
            }
        }
    }
}

有疑问加站长微信联系(非本文作者)

本文来自:新浪博客

感谢作者:stevewang

查看原文:[go语言]一种自适应资源分配器的实现

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2230 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传