数学之美-唯一ID生成算法

一切的合理性都可以通过数学来解释(自己瞎编的),今天就用数学给大家变个戏法,实现一个唯一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,再次重复的概率就好像中彩票可能性不大;数学真是美得不行!!!

发布了31 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_36557960/article/details/103812086