156 lines
2.7 KiB
Go
156 lines
2.7 KiB
Go
package common
|
||
|
||
import (
|
||
"math/rand"
|
||
"time"
|
||
)
|
||
|
||
const (
|
||
MAX_TRY_RAND_CNT = 10
|
||
RANDID_INVALID = -1
|
||
)
|
||
|
||
type BitPool struct {
|
||
flag []uint64
|
||
cnt int
|
||
}
|
||
|
||
func (bp *BitPool) Init(cnt int) {
|
||
bp.cnt = cnt/64 + 1
|
||
bp.flag = make([]uint64, bp.cnt, bp.cnt)
|
||
}
|
||
|
||
func (bp *BitPool) Mark(n int) bool {
|
||
idx := n / 64
|
||
off := n % 64
|
||
if idx < 0 || idx >= bp.cnt {
|
||
return false
|
||
}
|
||
|
||
bp.flag[idx] |= 1 << uint(off)
|
||
return true
|
||
}
|
||
|
||
func (bp *BitPool) Unmark(n int) bool {
|
||
idx := n / 64
|
||
off := n % 64
|
||
if idx < 0 || idx >= bp.cnt {
|
||
return false
|
||
}
|
||
|
||
bp.flag[idx] &= ^(1 << uint(off))
|
||
return true
|
||
}
|
||
|
||
func (bp *BitPool) IsMark(n int) bool {
|
||
idx := n / 64
|
||
off := n % 64
|
||
if idx < 0 || idx >= bp.cnt {
|
||
return false
|
||
}
|
||
|
||
return (bp.flag[idx] & (1 << uint(off))) != 0
|
||
}
|
||
|
||
type RandDistinctId struct {
|
||
rand *rand.Rand
|
||
bp BitPool
|
||
min int
|
||
max int
|
||
cap int
|
||
}
|
||
|
||
func NewRandDistinctId(min, max int) *RandDistinctId {
|
||
var id RandDistinctId
|
||
id.Init(min, max)
|
||
return &id
|
||
}
|
||
|
||
func (rid *RandDistinctId) Init(min, max int) {
|
||
rid.min = min
|
||
rid.max = max
|
||
rid.cap = max - min
|
||
rid.bp.Init(rid.cap)
|
||
rid.rand = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||
}
|
||
|
||
func (rid *RandDistinctId) Alloc(id int) bool {
|
||
if !rid.bp.IsMark(id) {
|
||
rid.bp.Mark(id)
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
func (rid *RandDistinctId) Free(id int) bool {
|
||
if rid.bp.IsMark(id) {
|
||
rid.bp.Unmark(id)
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
func (rid *RandDistinctId) RandOne() int {
|
||
for i := 0; i < MAX_TRY_RAND_CNT; i++ {
|
||
pos := rid.rand.Intn(rid.cap)
|
||
if !rid.bp.IsMark(pos) {
|
||
rid.bp.Mark(pos)
|
||
return pos + rid.min
|
||
}
|
||
}
|
||
|
||
//try one by one
|
||
rpos := rid.rand.Intn(rid.cap)
|
||
if rpos < rid.cap/2 {
|
||
for i := rpos; i >= 0; i-- {
|
||
if !rid.bp.IsMark(i) {
|
||
rid.bp.Mark(i)
|
||
return i + rid.min
|
||
}
|
||
}
|
||
} else {
|
||
for i := rpos; i < rid.cap; i++ {
|
||
if !rid.bp.IsMark(i) {
|
||
rid.bp.Mark(i)
|
||
return i + rid.min
|
||
}
|
||
}
|
||
}
|
||
return RANDID_INVALID
|
||
}
|
||
|
||
//func memConsumed() uint64 {
|
||
// runtime.GC() //GC,排除对象影响
|
||
// var memStat runtime.MemStats
|
||
// runtime.ReadMemStats(&memStat)
|
||
// return memStat.Sys
|
||
//}
|
||
|
||
//func main() {
|
||
// var idPool RandDistinctId
|
||
// before := memConsumed()
|
||
// idPool.Init(MIN, MAX)
|
||
// after := memConsumed()
|
||
//
|
||
// idMap := make(map[int]bool)
|
||
// for i := 0; i < 1000000; i++ {
|
||
// id := idPool.RandId()
|
||
// if id != -1 {
|
||
// idMap[id] = true
|
||
// }
|
||
// }
|
||
//
|
||
// start := time.Now()
|
||
// for i := 0; i < 10000; i++ {
|
||
// id := idPool.RandId()
|
||
// if id != -1 {
|
||
// fmt.Println(i, "->", id)
|
||
// idMap[id] = true
|
||
// }
|
||
//
|
||
// }
|
||
//
|
||
// fmt.Println("total take:", time.Now().Sub(start), " len:", len(idMap))
|
||
// fmt.Println(fmt.Sprintf("new %v pool consume %.3f MB", MAX-MIN, float64(after-before)/1024/1024))
|
||
//}
|