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

  在上一篇博文《利用缓冲信道来实现网游帐号验证消息的分发和等待中提到提到利用缓冲信道来实现数据包的分发和等待,并给出了一个原型实现。但是其中的缓冲信道有一个不足,即只能允许一定数量的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语言]一种自适应资源分配器的实现

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。