一切的合理性都可以通过数学来解释(自己瞎编的),今天就用数学给大家变个戏法,实现一个唯一ID生成器;而用到的数据知识包括排列组合+质数特性应用:
先给出一个数学定义:在一个质数集合中随意取出2n个质数,让他们两两相乘然后加和得m,放入后重新再取出2n个质数,经过相同步骤计算得出z,除非前后取出的质数相同且两两相乘的组合也相同,否则m != z(我拿着笔经过一阵噼里啪啦,验证得来的)。
所以当质数集合很大时,可以得到上千万种的排列组合,即上千万个唯一id,虽然在看起来还是很鸡肋的,但是在分布式应用,可以作为snowflow算法生成的唯一id中的seq部分,这样就不需要依赖任何服务去维护这个seq了,不需要依赖机器配置+中间件,就能实现一个分布式唯一id生成器(哪天去试着实现试试),通过上千万种的排列组合将一秒内生成两个相同id的可能性降到无限接近0。
甩出代码:
//生成唯一key
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"time"
)
const MAX_KEYS_CNT = 100000
const PL_BITS = 1024
const PL_BITS_MASK = 990
const PL_BITS2 = 4096
const PL_BITS2_MASK = 4095
var randoms []int64
var xuL []int64
var keys map[int64]bool
var cover int64
var maxKey int64
var randCt *rand.Rand
func keyRemove(cpRandoms []int64, index int) (int64, []int64) {
random := cpRandoms[index]
cpRandoms[len(cpRandoms)-1], cpRandoms[index] = cpRandoms[index], cpRandoms[len(cpRandoms)-1]
return random, cpRandoms[:len(cpRandoms)-1]
}
func init() {
randCt = rand.New(rand.NewSource(time.Now().UnixNano()))
randoms = make([]int64, 0, PL_BITS2)
xuL = make([]int64, 0, PL_BITS)
//测试
keys = make(map[int64]bool, MAX_KEYS_CNT)
fileA, err := os.OpenFile("zs_before.dat", os.O_RDONLY, 0755)
if err != nil {
fmt.Printf("file:`zs_before.dat`, err:`%v`\n", err)
}
defer fileA.Close()
fileB, err := os.OpenFile("zs_after.dat", os.O_RDONLY, 0755)
if err != nil {
fmt.Printf("file:`zs_after.dat`, err:`%v`\n", err)
}
defer fileB.Close()
scan := bufio.NewScanner(fileA)
countKey := 0
for scan.Scan() {
if countKey >= PL_BITS {
break;
}
intR, err := strconv.ParseInt(scan.Text(), 10, 64)
if err != nil {
fmt.Printf("err:`%v`\n", err)
break;
}
countKey++
xuL = append(xuL, intR)
}
scan = bufio.NewScanner(fileB)
countKey = 0
for scan.Scan() {
if countKey >= PL_BITS2 {
break;
}
intR, err := strconv.ParseInt(scan.Text(), 10, 64)
if err != nil {
fmt.Printf("err:`%v`\n", err)
break;
}
countKey++
randoms = append(randoms, intR)
}
}
func keyCreate() int64 {
var keyNumber, k int64 = 0, 0
initCnt := PL_BITS2
cpRandoms := randoms[:]
keysN := []int64{}
xlOffset := randCt.Intn(PL_BITS_MASK)
cpXuL := xuL[xlOffset:xlOffset+28]
for _, key := range cpXuL {
random := randCt.Intn(initCnt)&PL_BITS2_MASK
k, cpRandoms = keyRemove(cpRandoms, random)
keyNumber += key*k
keysN = append(keysN, k)
initCnt--
}
b, ok := keys[keyNumber]
if ok && b {
cover++
}
keys[keyNumber] = true;
if maxKey < keyNumber {
maxKey = keyNumber
}
return keyNumber
}
func main() {
t := time.Now()
for i := 0; i < MAX_KEYS_CNT; i++ {
keyCreate()
}
subXuL := xuL[:]
subRands := randoms[len(randoms)-len(xuL):]
var sum int64
for i, num := range subXuL {
sum += num*subRands[i]
}
fmt.Printf("cost:`%v`\n", time.Since(t))
fmt.Printf("max-key:`%v`, cover-`%d`\n", sum, cover)
}
实测:
看来这个`公式`还是很靠谱的!(结论,哈哈哈)
在生成10w个唯一seq测试中,平均出现唯一seq重复的次数为0.5,平均时间为174ms;
在生成100w个唯一seq测试中,平均出现唯一seq重复的次数为17.6,平均用时仅1.5s
总结:
在snowflow算法基础上,如果唯一id重复生成,延迟1s后,可以尝试重生成一个新的seq,再次重复的概率就好像中彩票可能性不大;数学真是美得不行!!!