实体池实现

来源:互联网 发布:ubuntu查看显卡使用率 编辑:程序博客网 时间:2024/06/05 09:50

实体池实现

引题

这里主要讲解不仅仅是实体池的实现,还有借鉴的编码规则,注视的格式,培养自己在以后的编码过程中养成好的习惯。

接口

池的设计,主要的就是取出和放回操作。每一个模块都需要有一定的自我
监控能力,可以反应自身的使用情况,因此真对实体池,我们提出实体总量和使用情况。接口具体如下:


// 实体池的接口类型。
type Pool interface {
Take() (Entity, error) // 取出实体
Return(entity Entity) error // 归还实体。
Total() uint32 // 实体池的容量。
Used() uint32 // 实体池中已被使用的实体的数量。
}

实现

在实现的过程中,需要计数实体总量,标志实体池的类型,因为要实现扩展性,我们需要外部提供一个函数作为实现实体的标准。还有容纳器包含实体,可以链表活着其他的,但是chan类型似乎更加的友好做为无状态链表操作。还有一个map用于标识实体是否正在用。当然作为并发组件,线程安全是必要的。

// 实体池的实现类型。type myPool struct {    total       uint32          // 池的总容量。    etype       reflect.Type    // 池中实体的类型。    genEntity   func() Entity   // 池中实体的生成函数。    container   chan Entity     // 实体容器。    idContainer map[uint32]bool // 实体ID的容器。    mutex       sync.Mutex      // 针对实体ID容器操作的互斥锁。

我们需要为每一个结构体提供NewXXX的函数,用于创建。注意这里创建的时候需要同时提供初始化整个实体池,这个池比较简单,是固定大小的,没有动态创建实体。灵活性不高,其实golang的包中提供了这种类似的池操作,大家可以看看源码如何实现。

// 创建实体池。func NewPool(    total uint32,    entityType reflect.Type,    genEntity func() Entity) (Pool, error) {    if total == 0 {        errMsg :=            fmt.Sprintf("The pool can not be initialized! (total=%d)\n", total)        return nil, errors.New(errMsg)    }    size := int(total)    container := make(chan Entity, size)    idContainer := make(map[uint32]bool)    for i := 0; i < size; i++ {        newEntity := genEntity()        if entityType != reflect.TypeOf(newEntity) {            errMsg :=                fmt.Sprintf("The type of result of function genEntity() is NOT %s!\n", entityType)            return nil, errors.New(errMsg)        }        container <- newEntity        idContainer[newEntity.Id()] = true    }    pool := &myPool{        total:       total,        etype:       entityType,        genEntity:   genEntity,        container:   container,        idContainer: idContainer,    }    return pool, nil}

下面直接给出整个接口函数的实现,不做一一讲解

func (pool *myPool) Take() (Entity, error) {    entity, ok := <-pool.container    if !ok {        return nil, errors.New("The inner container is invalid!")    }    pool.mutex.Lock()    defer pool.mutex.Unlock()    pool.idContainer[entity.Id()] = false    return entity, nil}func (pool *myPool) Return(entity Entity) error {    if entity == nil {        return errors.New("The returning entity is invalid!")    }    if pool.etype != reflect.TypeOf(entity) {        errMsg := fmt.Sprintf("The type of returning entity is NOT %s!\n", pool.etype)        return errors.New(errMsg)    }    entityId := entity.Id()    casResult := pool.compareAndSetForIdContainer(entityId, false, true)    if casResult == 1 {        pool.container <- entity        return nil    } else if casResult == 0 {        errMsg := fmt.Sprintf("The entity (id=%d) is already in the pool!\n", entityId)        return errors.New(errMsg)    } else {        errMsg := fmt.Sprintf("The entity (id=%d) is illegal!\n", entityId)        return errors.New(errMsg)    }}// 比较并设置实体ID容器中与给定实体ID对应的键值对的元素值。// 结果值://       -1:表示键值对不存在。//        0:表示操作失败。//        1:表示操作成功。func (pool *myPool) compareAndSetForIdContainer(    entityId uint32, oldValue bool, newValue bool) int8 {    pool.mutex.Lock()    defer pool.mutex.Unlock()    v, ok := pool.idContainer[entityId]    if !ok {        return -1    }    if v != oldValue {        return 0    }    pool.idContainer[entityId] = newValue    return 1}func (pool *myPool) Total() uint32 {    return pool.total}func (pool *myPool) Used() uint32 {    return pool.total - uint32(len(pool.container))}

感悟

主要感悟在于编码的格式,在哪里写注释,在哪里定义,变量的命名格式都有了新的了解和学习。

原创粉丝点击