2020-12-28 05:11:31 +08:00

90 lines
2.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 薄雾算法
*
* 1 2 48 56 64
* +------+-----------------------------------------------------+----------+----------+
* retain | increas | salt | sequence |
* +------+-----------------------------------------------------+----------+----------+
* 0 | 0000000000 0000000000 0000000000 0000000000 0000000 | 00000000 | 00000000 |
* +------+-----------------------------------------------------+------------+--------+
*
* 0. 最高位,占 1 位,保持为 0使得值永远为正数
* 1. 自增数,占 47 位,自增数在高位能保证结果值呈递增态势,遂低位可以为所欲为;
* 2. 随机因子一,占 8 位,上限数值 255使结果值不可预测
* 3. 随机因子二,占 8 位,上限数值 255使结果值不可预测
*
* 编号上限为百万亿级,上限值计算为 140737488355327 即 int64(1 << 47 - 1),假设每天取值 10 亿,能使用 385+ 年
*/
package main
import (
"crypto/rand"
"fmt"
"math/big"
"strconv"
"sync"
"time"
)
const startYear = 2019
const saltBit = uint(8) // 随机因子二进制位数
const saltShift = uint(8) // 随机因子移位数
const increasShift = saltBit + saltShift // 自增数移位数
func NewIncreaserFromTime(t time.Time) int64 {
year := t.Year() - startYear
day := t.YearDay()
secs := 60*60*t.Hour() + 60*t.Minute() + t.Second()
s := fmt.Sprintf("%d%d%05d", year, day, secs)
v, _ := strconv.ParseInt(s, 10, 64)
return v
}
type Mist struct {
sync.Mutex // 互斥锁
increas int64 // 自增数
saltA int64 // 随机因子一
saltB int64 // 随机因子二
}
/* 初始化 Mist 结构体*/
func NewMist(c int64) *Mist {
mist := Mist{increas: c}
return &mist
}
/* 生成唯一编号 */
func (c *Mist) Generate() int64 {
c.Lock()
defer c.Unlock()
c.increas++
// 获取随机因子数值 使用真随机函数提高性能
randA, _ := c.newRand()
c.saltA = randA.Int64()
randB, _ := c.newRand()
c.saltB = randB.Int64()
// 通过位运算实现自动占位
mist := int64((c.increas << increasShift) | (c.saltA << saltShift) | c.saltB)
return mist
}
func (c Mist) newRand() (*big.Int, error) {
return rand.Int(rand.Reader, big.NewInt(255))
}
func main() {
// 使用方法
// mist := NewMist(NewIncreaserFromTime(time.Now()))
mist := NewMist(31175572)
m := make(map[int64]int)
for i := 0; i < 10; i++ {
v := mist.Generate()
if _, ok := m[v]; ok {
fmt.Println(v, i)
}
m[v] = i
fmt.Println(v)
}
}